Mercurial > kinput2.yaz
view lib/imlib/imattr.c @ 0:92745d501b9a
initial import from kinput2-v3.1
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Mon, 08 Mar 2010 04:44:30 +0900 |
parents | |
children | 1f9e9cb00c6c |
line wrap: on
line source
#ifndef lint static char *rcsid = "$Id: imattr.c,v 1.18 2002/01/10 15:04:05 ishisone Exp $"; #endif /* * Copyright (c) 1994 Software Research Associates, Inc. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Software Research Associates not be * used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. Software Research * Associates makes no representations about the suitability of this software * for any purpose. It is provided "as is" without express or implied * warranty. * * Author: Makoto Ishisone, Software Research Associates, Inc., Japan */ #include "im.h" #ifndef XNSeparatorofNestedList #define XNSeparatorofNestedList "separatorofNesttedList" #endif #ifndef XNPreeditState #define XNPreeditState "preeditState" #endif #ifndef XIMPreeditEnable #define XIMPreeditEnable 1L #define XIMPreeditDisable 2L #endif #ifndef XNResetState #define XNResetState "resetState" #endif #ifndef XIMInitialState #define XIMInitialState 1L #define XIMPreserveState 2L #endif #define PAD4(n) ((((n) + 3) / 4) * 4) /* * List of supported input styles. */ typedef struct { XIMStyle xim_style; /* X11R5 spec. */ int conversion_style; /* kinput2 spec. */ } InputStyle; static InputStyle styles[] = { { XIMPreeditPosition|XIMStatusArea, IMSTYLE_OVER_THE_SPOT }, { XIMPreeditPosition|XIMStatusNothing, IMSTYLE_OVER_THE_SPOT }, { XIMPreeditArea|XIMStatusArea, IMSTYLE_OFF_THE_SPOT }, { XIMPreeditCallbacks|XIMStatusCallbacks, IMSTYLE_ON_THE_SPOT }, { XIMPreeditCallbacks|XIMStatusNothing, IMSTYLE_ON_THE_SPOT }, { XIMPreeditNothing|XIMStatusNothing, IMSTYLE_SEPARATE }, { 0 }, }; #define NEST_NONE 0 #define NEST_PREEDIT 1 #define NEST_STATUS 2 #define CHECK_ICATTR_SIZE(validsize, code) \ if (len != validsize) { badSizeError(icp, code); return -1; } #undef OP_C #undef OP_S #undef OP_G #define OP_C 1 /* Create */ #define OP_S 2 /* SetValues */ #define OP_G 4 /* GetValues */ typedef struct { char *name; /* attribute name */ int type; /* type of attribute value */ int valid_ops; /* valid operations for this attribute */ int (*set_proc) _Pt_((IMIM *, char *, int)); int (*get_proc) _Pt_((IMIM *, unsigned int, int)); } IMAttribute; typedef struct { char *name; /* attribute name */ int type; /* type of attribute value */ int valid_ops; /* valid operations for this attribute */ int (*set_proc) _Pt_((IMIC *, char *, int, int, int, int)); int (*get_proc) _Pt_((IMIC *, unsigned int, int, int, char *, int)); } ICAttribute; /* * IM attributes */ static int getQueryInputStyle _Pt_((IMIM *imp, unsigned int id, int offset)); static IMAttribute imAttributes[] = { { XNQueryInputStyle, TYPE_XIM_STYLES, OP_G, NULL, getQueryInputStyle }, }; static int numImAttributes = XtNumber(imAttributes); /* * IC attributes */ static int setInputStyle _Pt_((IMIC *, char *, int, int, int, int)); static int setClientWindow _Pt_((IMIC *, char *, int, int, int, int)); static int setFocusWindow _Pt_((IMIC *, char *, int, int, int, int)); static int setPreeditAttributes _Pt_((IMIC *, char *, int, int, int, int)); static int setStatusAttributes _Pt_((IMIC *, char *, int, int, int, int)); static int setArea _Pt_((IMIC *, char *, int, int, int, int)); static int setAreaNeeded _Pt_((IMIC *, char *, int, int, int, int)); static int setForeground _Pt_((IMIC *, char *, int, int, int, int)); static int setBackground _Pt_((IMIC *, char *, int, int, int, int)); static int setColormap _Pt_((IMIC *, char *, int, int, int, int)); static int setBgPixmap _Pt_((IMIC *, char *, int, int, int, int)); static int setLineSpace _Pt_((IMIC *, char *, int, int, int, int)); static int setCursor _Pt_((IMIC *, char *, int, int, int, int)); static int setSpotLocation _Pt_((IMIC *, char *, int, int, int, int)); static int setStdColormap _Pt_((IMIC *, char *, int, int, int, int)); static int setFontSet _Pt_((IMIC *, char *, int, int, int, int)); static int setPreeditState _Pt_((IMIC *, char *, int, int, int, int)); static int setResetState _Pt_((IMIC *, char *, int, int, int, int)); static int getPreeditAttributes _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getStatusAttributes _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getInputStyle _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getClientWindow _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getFocusWindow _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getFilterEvents _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getArea _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getAreaNeeded _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getSpotLocation _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getColormap _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getStdColormap _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getForeground _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getBackground _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getBgPixmap _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getFontSet _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getLineSpace _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getCursor _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getPreeditState _Pt_((IMIC *, unsigned int, int, int, char *, int)); static int getResetState _Pt_((IMIC *, unsigned int, int, int, char *, int)); static ICAttribute icAttributes[] = { { XNInputStyle, TYPE_CARD32, OP_C|OP_G, setInputStyle, getInputStyle }, { XNClientWindow, TYPE_WINDOW, OP_C|OP_S|OP_G, setClientWindow, getClientWindow }, { XNFocusWindow, TYPE_WINDOW, OP_C|OP_S|OP_G, setFocusWindow, getFocusWindow }, { XNFilterEvents, TYPE_CARD32, OP_G, NULL, getFilterEvents }, { XNPreeditAttributes, TYPE_NESTED_LIST, OP_C|OP_S|OP_G, setPreeditAttributes, getPreeditAttributes }, { XNStatusAttributes, TYPE_NESTED_LIST, OP_C|OP_S|OP_G, setStatusAttributes, getStatusAttributes }, { XNArea, TYPE_XRECTANGLE, OP_C|OP_S|OP_G, setArea, getArea }, { XNAreaNeeded, TYPE_XRECTANGLE, OP_C|OP_S|OP_G, setAreaNeeded, getAreaNeeded }, { XNSpotLocation, TYPE_XPOINT, OP_C|OP_S|OP_G, setSpotLocation, getSpotLocation }, { XNColormap, TYPE_CARD32, OP_C|OP_S|OP_G, setColormap, getColormap }, { XNStdColormap, TYPE_CARD32, OP_C|OP_S|OP_G, setStdColormap, getStdColormap }, { XNForeground, TYPE_CARD32, OP_C|OP_S|OP_G, setForeground, getForeground }, { XNBackground, TYPE_CARD32, OP_C|OP_S|OP_G, setBackground, getBackground }, { XNBackgroundPixmap, TYPE_CARD32, OP_C|OP_S|OP_G, setBgPixmap, getBgPixmap }, { XNFontSet, TYPE_XFONTSET, OP_C|OP_S|OP_G, setFontSet, getFontSet }, { XNLineSpace, TYPE_CARD16, OP_C|OP_S|OP_G, /* should be TYPE_INT16 */ setLineSpace, getLineSpace }, { XNCursor, TYPE_CARD32, OP_C|OP_S|OP_G, setCursor, getCursor }, { XNSeparatorofNestedList, TYPE_SEPARATOR, OP_G, NULL, NULL }, { XNPreeditState, TYPE_CARD32, OP_C|OP_S|OP_G, setPreeditState, getPreeditState }, { XNResetState, TYPE_CARD32, OP_C|OP_S|OP_G, setResetState, getResetState }, }; static int numIcAttributes = XtNumber(icAttributes); static unsigned int getC16 _Pt_((char *data, int order)); static int getI16 _Pt_((char *data, int order)); static unsigned long getC32 _Pt_((char *data, int order)); static int validateClientWindow _Pt_((IMIC *icp)); static int validateFocusWindow _Pt_((IMIC *icp)); static void badSizeError _Pt_((IMIC *icp, int code)); static void unnestedError _Pt_((IMIC *icp)); static IMPSAttributes *getPSPtr _Pt_((IMIC *icp, int type)); static int getIMValues _Pt_((IMIM *imp, char *data, int len, int offset)); static int getICValues _Pt_((IMIC *icp, char *data, int len, int nest, int offset, int *sepp)); static int setICValues _Pt_((IMIC *icp, char *data, int len, int major, int op)); static int getPSAttributes _Pt_((IMIC *icp, unsigned int id, int nest, int offset, char *data, int len)); static void changeFonts _Pt_((IMIC *icp, int preedit)); static void fillCommonDefault _Pt_((IMIC *icp, unsigned long mask)); static int getNaturalLineSpace _Pt_((IMIC *icp, int preedit)); static void fillPSDefault _Pt_((IMIC *icp, int type, unsigned long mask)); static int validateCommonAttr _Pt_((IMIC *icp, int checkonly)); static int validatePSAttr _Pt_((IMIC *icp, int type, int checkonly)); static void changeConversionAttributes _Pt_((IMIC *icp)); static void computeAreaNeeded _Pt_((IMIC *icp)); static void computeAreaForQuery _Pt_((IMIC *icp)); /* * Functions reading out numbers from byte buffer */ static unsigned int getC16(data, order) char *data; int order; { unsigned char *p = (unsigned char *)data; unsigned int x; x = (order == ORDER_BIG) ? ((p[0] << 8) | p[1]) : (p[0] | p[1] << 8); return x; } static int getI16(data, order) char *data; int order; { unsigned char *p = (unsigned char *)data; long l; l = (order == ORDER_BIG) ? ((p[0] << 8) | p[1]) : (p[0] | p[1] << 8); return (l < 32768) ? (int)l : (int)(l - 65536L); } static unsigned long getC32(data, order) char *data; int order; { unsigned char *p = (unsigned char *)data; unsigned long x; if (order == ORDER_BIG) { x = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; } else { x = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); } return x; } /* * Functions that check the validity of resources. */ static int validateClientWindow(icp) IMIC *icp; { return IMValidateWindow(XtDisplay(icp->im->connection->proto_widget), icp->common_attr.client, &icp->client_profile); } static int validateFocusWindow(icp) IMIC *icp; { IMCommonAttributes *ap = &icp->common_attr; /* * This function assumes that the client window has already * been validated. */ if ((ap->set_mask & ATTR_MASK_CLIENT) && ap->focus == ap->client) { icp->focus_profile = icp->client_profile; return 1; } else { return IMValidateWindow(XtDisplay(icp->im->connection->proto_widget), icp->common_attr.focus, &icp->focus_profile); } } /* * Functions submit errors */ static void badSizeError(icp, code) IMIC *icp; int code; { DPRINT(("bad size error for IC #%d\n", icp->id)); IMSendError(icp->im->connection, code, icp->im->id, icp->id, "invalid size of attribute value"); } static void unnestedError(icp) IMIC *icp; { DPRINT(("unnested error for IC #%d\n", icp->id)); IMSendError(icp->im->connection, IMBadSomething, icp->im->id, icp->id, "either preedit or status specification required"); } /* * Functions getting IM attributes */ static IMPSAttributes * getPSPtr(icp, type) IMIC *icp; int type; { switch (type) { case NEST_PREEDIT: return &icp->preedit_attr; case NEST_STATUS: return &icp->status_attr; default: return NULL; } } static int getIMValues(imp, data, len, offset) IMIM *imp; char *data; int len; int offset; /* request offset */ { unsigned int id; /* attribute ID */ IMAttribute *attrp; IMConnection *conn = imp->connection; int byte_order = conn->byte_order; while (len >= 2) { id = getC16(data, byte_order); data += 2; len -= 2; if (id > numImAttributes) { /* invalid attribute ID */ IMCancelRequest(conn, offset); IMSendError(conn, IMBadSomething, imp->id, 0, "invalid IM attribute ID"); return -1; } attrp = &imAttributes[id]; if (!(attrp->valid_ops & OP_G)) { IMCancelRequest(conn, offset); IMSendError(conn, IMBadSomething, imp->id, 0, "invalid operation (IMGetValues) for this attribute"); return -1; } if ((*attrp->get_proc)(imp, id, offset) < 0) return -1; } return 0; } /* ARGSUSED */ static int getQueryInputStyle(imp, id, offset) IMIM *imp; unsigned int id; int offset; { IMConnection *conn = imp->connection; unsigned int num_styles, num_bytes; InputStyle *stp; TRACE(("imlib:getQueryInputStyle()\n")); for (num_styles = 0, stp = styles; stp->xim_style != 0; stp++) { num_styles++; } num_bytes = num_styles * 4 + 4; IMPutC16(conn, id); IMPutC16(conn, num_bytes); IMPutC16(conn, num_styles); IMPutC16(conn, 0); for (stp = styles; stp->xim_style != 0; stp++) { IMPutC32(conn, stp->xim_style); } return 0; } /* * Functions setting IC attributes */ static int setICValues(icp, data, len, nest, op) IMIC *icp; char *data; int len; int nest; int op; { IMConnection *conn = icp->im->connection; unsigned int imid = icp->im->id; unsigned int icid = icp->id; unsigned int id; unsigned int value_len; unsigned int attr_len; char *value; ICAttribute *attrp; int byte_order = icp->im->connection->byte_order; TRACE(("imlib:setICValues()\n")); while (len > 0) { if (len < 4) { DPRINT(("attribute data length < 4\n")); IMSendError(conn, IMBadSomething, imid, icid, "Bad attribute data"); return -1; } id = getC16(data, byte_order); value_len = getC16(data + 2, byte_order); attr_len = PAD4(4 + value_len); if (attr_len > len) { DPRINT(("attribute data length > request length\n")); IMSendError(conn, IMBadSomething, imid, icid, "Bad attribute length"); return -1; } value = data + 4; if (id > numIcAttributes) { DPRINT(("invalid IC attribute ID %d\n", id)); IMSendError(conn, IMBadSomething, imid, icid, "invalid IC attribute ID"); return -1; } attrp = &icAttributes[id]; if (!(attrp->valid_ops & op)) { DPRINT(("invalid operation (%s) for IC attr %d\n", op == OP_C ? "create" : "set", id)); IMSendError(conn, IMBadSomething, imid, icid, "invalid operation for this attribute"); return -1; } /* * Call attribute set procedure. */ if ((*attrp->set_proc)(icp, value, (int)value_len, byte_order, nest, op) < 0) { /* * Error has occured. The set procedure has already sent * appropriate error message, so just return here. */ return -1; } data += attr_len; len -= attr_len; } return 0; } /* ARGSUSED */ static int setInputStyle(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { TRACE(("imlib:setInputStyle()\n")); CHECK_ICATTR_SIZE(4, IMBadStyle); /* * InputStyle must be set with CreateIC. */ if (op != OP_C) { DPRINT(("trying to change input style through SetICValues\n")); IMSendError(icp->im->connection, IMBadStyle, icp->im->id, icp->id, "InputStyle cannot be changed by SetICValues"); return -1; } icp->common_attr.input_style = (XIMStyle)getC32(value, order); icp->common_attr.set_mask |= ATTR_MASK_INPUT_STYLE; icp->common_attr.change_mask |= ATTR_MASK_INPUT_STYLE; TRACE(("\tinput style: %ld\n", icp->common_attr.input_style)); return 0; } /* ARGSUSED */ static int setClientWindow(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { TRACE(("imlib:setClientWindow()\n")); CHECK_ICATTR_SIZE(4, IMBadClientWindow); /* * ClientWindow cannot be changed. */ if (icp->common_attr.set_mask & ATTR_MASK_CLIENT) { DPRINT(("client window already specified\n")); IMSendError(icp->im->connection, IMBadClientWindow, icp->im->id, icp->id, "ClientWindow already set"); return -1; } icp->common_attr.client = (Window)getC32(value, order); TRACE(("\tclient window: %08lx\n", icp->common_attr.client)); icp->common_attr.set_mask |= ATTR_MASK_CLIENT; icp->common_attr.change_mask |= ATTR_MASK_CLIENT; return 0; } /* ARGSUSED */ static int setFocusWindow(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { Window focus; TRACE(("imlib:setFocusWindow()\n")); CHECK_ICATTR_SIZE(4, IMBadFocusWindow); focus = (Window)getC32(value, order); TRACE(("\tfocus window: %08lx\n", focus)); if (!(icp->common_attr.set_mask & ATTR_MASK_FOCUS) || focus != icp->common_attr.focus) { icp->common_attr.change_mask |= ATTR_MASK_FOCUS; } icp->common_attr.focus = focus; icp->common_attr.set_mask |= ATTR_MASK_FOCUS; return 0; } /* ARGSUSED */ static int setPreeditAttributes(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { TRACE(("imlib:setPreeditAttributes()\n")); return setICValues(icp, value, len, NEST_PREEDIT, op); } /* ARGSUSED */ static int setStatusAttributes(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { TRACE(("imlib:setStatusAttributes()\n")); return setICValues(icp, value, len, NEST_STATUS, op); } /* ARGSUSED */ static int setArea(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMPSAttributes *ap; XRectangle area; TRACE(("imlib:setArea()\n")); CHECK_ICATTR_SIZE(8, IMBadArea); if ((ap = getPSPtr(icp, nest)) == NULL) { unnestedError(icp); return -1; } area.x = getI16(value, order); area.y = getI16(value + 2, order); area.width = getC16(value + 4, order); area.height = getC16(value + 6, order); TRACE(("\tarea: %d, %d, %d, %d\n", area.x, area.y, area.width, area.height)); if (!(ap->set_mask & ATTR_MASK_AREA) || area.x != ap->area.x || area.y != ap->area.y || area.width != ap->area.width || area.height != ap->area.height) { ap->change_mask |= ATTR_MASK_AREA; } ap->area.x = area.x; ap->area.y = area.y; ap->area.width = area.width; ap->area.height = area.height; ap->set_mask |= ATTR_MASK_AREA; return 0; } /* ARGSUSED */ static int setAreaNeeded(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMPSAttributes *ap; XRectangle area; TRACE(("imlib:setAreaNeeded()\n")); CHECK_ICATTR_SIZE(8, IMBadArea); if ((ap = getPSPtr(icp, nest)) == NULL) { unnestedError(icp); return -1; } area.width = getC16(value + 4, order); area.height = getC16(value + 6, order); TRACE(("\tarea needed: %d, %d\n", area.width, area.height)); if (!(ap->set_mask & ATTR_MASK_AREA_NEEDED) || area.width != ap->area_needed.width || area.height != ap->area_needed.height) { ap->change_mask |= ATTR_MASK_AREA_NEEDED; } ap->area_needed.width = area.width; ap->area_needed.height = area.height; ap->set_mask |= ATTR_MASK_AREA_NEEDED; return 0; } /* ARGSUSED */ static int setForeground(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMPSAttributes *ap; Pixel fore; TRACE(("imlib:setForeground()\n")); CHECK_ICATTR_SIZE(4, IMBadForeground); if ((ap = getPSPtr(icp, nest)) == NULL) { unnestedError(icp); return -1; } fore = getC32(value, order); TRACE(("\tforeground: %ld\n", fore)); if (!(ap->set_mask & ATTR_MASK_FOREGROUND) || fore != ap->foreground) { ap->change_mask |= ATTR_MASK_FOREGROUND; } ap->foreground = fore; ap->set_mask |= ATTR_MASK_FOREGROUND; return 0; } /* ARGSUSED */ static int setBackground(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMPSAttributes *ap; Pixel back; TRACE(("imlib:setBackground()\n")); CHECK_ICATTR_SIZE(4, IMBadBackground); if ((ap = getPSPtr(icp, nest)) == NULL) { unnestedError(icp); return -1; } back = getC32(value, order); TRACE(("\tbackground: %ld\n", back)); if (!(ap->set_mask & ATTR_MASK_BACKGROUND) || back != ap->background) { ap->change_mask |= ATTR_MASK_BACKGROUND; } ap->background = back; ap->set_mask |= ATTR_MASK_BACKGROUND; return 0; } /* ARGSUSED */ static int setColormap(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMPSAttributes *ap; Colormap cmap; TRACE(("imlib:setColormap()\n")); CHECK_ICATTR_SIZE(4, IMBadColormap); if ((ap = getPSPtr(icp, nest)) == NULL) { unnestedError(icp); return -1; } cmap = getC32(value, order); TRACE(("\tcolormap: %08lx\n", cmap)); if (!(ap->set_mask & ATTR_MASK_COLORMAP) || cmap != ap->colormap) { ap->change_mask |= ATTR_MASK_COLORMAP; } ap->colormap = cmap; ap->set_mask |= ATTR_MASK_COLORMAP; return 0; } /* ARGSUSED */ static int setBgPixmap(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMPSAttributes *ap; Pixmap pixmap; TRACE(("imlib:setBgPixmap()\n")); CHECK_ICATTR_SIZE(4, IMBadPixmap); if ((ap = getPSPtr(icp, nest)) == NULL) { unnestedError(icp); return -1; } pixmap = getC32(value, order); TRACE(("\tbackground pixmap: %08lx\n", pixmap)); if (!(ap->set_mask & ATTR_MASK_BG_PIXMAP) || pixmap != ap->bg_pixmap) { ap->change_mask |= ATTR_MASK_BG_PIXMAP; } ap->bg_pixmap = pixmap; ap->set_mask |= ATTR_MASK_BG_PIXMAP; return 0; } /* ARGSUSED */ static int setLineSpace(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMPSAttributes *ap; int line_space; TRACE(("imlib:setLineSpace()\n")); CHECK_ICATTR_SIZE(2, IMBadSomething); if ((ap = getPSPtr(icp, nest)) == NULL) { unnestedError(icp); return -1; } line_space = getI16(value, order); /* ??? linespacing is 'int' */ TRACE(("\tline space: %d\n", line_space)); if (!(ap->set_mask & ATTR_MASK_LINESPACE) || line_space != ap->line_space) { ap->change_mask |= ATTR_MASK_LINESPACE; } ap->line_space = line_space; ap->set_mask |= ATTR_MASK_LINESPACE; return 0; } /* ARGSUSED */ static int setCursor(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMPSAttributes *ap; Cursor cursor; TRACE(("imlib:setCursor()\n")); CHECK_ICATTR_SIZE(4, IMBadCursor); if ((ap = getPSPtr(icp, nest)) == NULL) { unnestedError(icp); return -1; } cursor = getC32(value, order); TRACE(("\tcursor: %08lx\n", cursor)); if (!(ap->set_mask & ATTR_MASK_CURSOR) || cursor != ap->cursor) { ap->change_mask |= ATTR_MASK_CURSOR; } ap->cursor = cursor; ap->set_mask |= ATTR_MASK_CURSOR; return 0; } /* ARGSUSED */ static int setSpotLocation(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMPSAttributes *ap; XPoint spot; TRACE(("imlib:setSpotLocation()\n")); CHECK_ICATTR_SIZE(4, IMBadSpotLocation); if (nest == NEST_STATUS) { DPRINT(("spot location specified in a status attribute list\n")); IMSendError(icp->im->connection, IMBadSpotLocation, icp->im->id, icp->id, "spot location isn't a status attribute"); return -1; } ap = &icp->preedit_attr; spot.x = getI16(value, order); spot.y = getI16(value + 2, order); TRACE(("\tspot location: %d, %d\n", spot.x, spot.y)); if (!(ap->set_mask & ATTR_MASK_SPOT_LOCATION) || spot.x != ap->spot_location.x || spot.y != ap->spot_location.y) { ap->change_mask |= ATTR_MASK_SPOT_LOCATION; } ap->spot_location.x = spot.x; ap->spot_location.y = spot.y; ap->set_mask |= ATTR_MASK_SPOT_LOCATION; return 0; } /* ARGSUSED */ static int setStdColormap(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMPSAttributes *ap; Atom colormap_name; XStandardColormap *stdcolormaps; Widget w = icp->im->connection->proto_widget; Display *dpy = XtDisplay(w); int ncolormaps; Window root; XAEHandle h; int status; TRACE(("imlib:setStdColormap()\n")); CHECK_ICATTR_SIZE(4, IMBadAtom); if ((ap = getPSPtr(icp, nest)) == NULL) { unnestedError(icp); return -1; } colormap_name = getC32(value, order); if (icp->common_attr.set_mask & ATTR_MASK_CLIENT) { root = icp->client_profile.root; } else if (icp->common_attr.set_mask & ATTR_MASK_FOCUS) { root = icp->focus_profile.root; } else { /* * Client has not specified client window yet. * Reading standard colormap property should been deffered * until the window is set, but for now... */ DDPRINT(2, ("std colormap specified, leaving client window unspecified\n")); root = RootWindowOfScreen(XtScreen(w)); } h = XAESetIgnoreErrors(dpy); status = XGetRGBColormaps(dpy, root, &stdcolormaps, &ncolormaps, colormap_name); XAEUnset(h); if (!status || ncolormaps < 0) { DPRINT(("can't get standard colormap (%ld)\n", colormap_name)); IMSendError(icp->im->connection, IMBadName, icp->im->id, icp->id, "invalid standard colormap name"); return -1; } if (!(ap->set_mask & ATTR_MASK_STD_COLORMAP) || colormap_name != ap->std_colormap) { ap->change_mask |= ATTR_MASK_STD_COLORMAP; } ap->std_colormap = colormap_name; ap->colormap = stdcolormaps[0].colormap; TRACE(("\tstandard colormap: %ld (colormap=%08lx)\n", colormap_name, ap->colormap)); ap->set_mask |= ATTR_MASK_STD_COLORMAP | ATTR_MASK_COLORMAP; XFree((char *)stdcolormaps); return 0; } /* ARGSUSED */ static int setFontSet(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMPSAttributes *ap; unsigned int name_list_len; char *name_list; TRACE(("imlib:setFontSet()\n")); if (len < 2) { badSizeError(icp, IMBadName); return -1; } name_list_len = getC16(value, order); if (2 + name_list_len > len) { badSizeError(icp, IMBadName); return -1; } if ((ap = getPSPtr(icp, nest)) == NULL) { unnestedError(icp); return -1; } name_list = XtMalloc(name_list_len + 1); bcopy(value + 2, name_list, name_list_len); name_list[name_list_len] = '\0'; TRACE(("\tfontset: %s\n", name_list)); if (ap->set_mask & ATTR_MASK_FONT_SET) { if (!strcmp(name_list, ap->font_set)) { XtFree(name_list); } else { ap->change_mask |= ATTR_MASK_FONT_SET; if (ap->font_set != IMDefaultFontSet(icp->im)) { XtFree(ap->font_set); } ap->font_set = name_list; } } else { ap->font_set = name_list; ap->set_mask |= ATTR_MASK_FONT_SET; ap->change_mask |= ATTR_MASK_FONT_SET; } return 0; } /* ARGSUSED */ static int setPreeditState(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMCommonAttributes *ap = &icp->common_attr; unsigned long preedit_state; TRACE(("imlib:setPreeditState()\n")); CHECK_ICATTR_SIZE(4, IMBadSomething); if (nest == NEST_STATUS) { DPRINT(("preedit state specified in a status attribute list\n")); IMSendError(icp->im->connection, IMBadSomething, icp->im->id, icp->id, "preedit state isn't a status attribute"); return -1; } preedit_state = getC32(value, order); ap->set_mask |= ATTR_MASK_PREEDIT_STATE; ap->change_mask |= ATTR_MASK_PREEDIT_STATE; ap->preedit_state = preedit_state; return 0; } /* ARGSUSED */ static int setResetState(icp, value, len, order, nest, op) IMIC *icp; char *value; int len; int order; int nest; int op; { IMCommonAttributes *ap = &icp->common_attr; unsigned long reset_state; TRACE(("imlib:setResetState()\n")); CHECK_ICATTR_SIZE(4, IMBadSomething); reset_state = getC32(value, order); ap->set_mask |= ATTR_MASK_RESET_STATE; ap->change_mask |= ATTR_MASK_RESET_STATE; ap->reset_state = reset_state; return 0; } /* * Functions getting IC attributes */ static int getICValues(icp, data, len, nest, offset, sepp) IMIC *icp; char *data; int len; int nest; /* NEST_NONE, NEST_PREEDIT or NEST_STATUS */ int offset; /* request offset */ int *sepp; /* Out: true if ended with a nested list separator */ { unsigned int id; /* attribute ID */ ICAttribute *attrp; IMConnection *conn = icp->im->connection; int byte_order = conn->byte_order; char *org_data = data; int r; TRACE(("imlib:getICValues()\n")); while (len >= 2) { id = getC16(data, byte_order); data += 2; len -= 2; if (id > numIcAttributes) { /* invalid attribute ID */ DPRINT(("invalid IC attribute ID (%d) specified\n", id)); IMCancelRequest(conn, offset); IMSendError(conn, IMBadSomething, icp->im->id, icp->id, "invalid IC attribute ID"); return -1; } attrp = &icAttributes[id]; if (attrp->type == TYPE_SEPARATOR) { /* nested list separator */ *sepp = 1; return data - org_data; } if (!(attrp->valid_ops & OP_G)) { DPRINT(("invalid operation (get) for IC attr %d\n", id)); IMCancelRequest(conn, offset); IMSendError(conn, IMBadSomething, icp->im->id, icp->id, "invalid operation (ICGetValues) for this attribute"); return -1; } r = (*attrp->get_proc)(icp, id, nest, offset, data, len); /* * The return value of get_proc is usually 0, indicating success. * If it is less than 0, there are some errors. * If it is greater than 0, */ if (r < 0) return -1; data += r; /* r is extra offset */ len -= r; } *sepp = 0; return data - org_data; } /* ARGSUSED */ static int getPSAttributes(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; unsigned int length; int length_offset; int attr_offset; int nested_separator; int r; IMPutC16(conn, id); length_offset = IMWritePos(conn); IMPutC16(conn, 0); /* dummy -- overwritten afterwards */ attr_offset = IMWritePos(conn); r = getICValues(icp, data, len, nest, offset, &nested_separator); if (r < 0) return -1; if (!nested_separator) { /* there's no nested list separator */ DPRINT(("nested list doesn't end with separator\n")); /* * X11R6 Xlib sends nested attribute list which has no * separator at its end. In order to accommodate to it, * don't send error for that. */ #ifdef notdef IMCancelRequest(conn, offset); IMSendError(conn, IMBadSomething, icp->im->id, icp->id, "corrupted nested list"); return -1; #endif } /* * Nested list is written on the output buffer. * Calculate the length of the list. */ length = IMWritePos(conn) - attr_offset; /* rewrite attribute length field */ IMRewriteC16(conn, length_offset, length); IMPutPad(conn); return r; } /* ARGSUSED */ static int getPreeditAttributes(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; /* unused */ int offset; char *data; int len; { TRACE(("imlib:getPreeditAttributes()\n")); return getPSAttributes(icp, id, NEST_PREEDIT, offset, data, len); } /* ARGSUSED */ static int getStatusAttributes(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; /* unused */ int offset; char *data; int len; { TRACE(("imlib:getStatusAttributes()\n")); return getPSAttributes(icp, id, NEST_STATUS, offset, data, len); } /* ARGSUSED */ static int getInputStyle(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; TRACE(("imlib:getInputStyle()\n")); /* * Input style must have been specified, (and validated) * at IC creation. No need for checking. */ IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, icp->common_attr.input_style); return 0; } /* ARGSUSED */ static int getClientWindow(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; TRACE(("imlib:getClientWindow()\n")); if (icp->common_attr.set_mask & ATTR_MASK_CLIENT) { IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, icp->common_attr.client); return 0; } else { /* no default is available */ DPRINT(("getClientWindow without setting client window previously\n")); IMCancelRequest(conn, offset); IMSendError(conn, IMBadClientWindow, icp->im->id, icp->id, "client window not specified yet"); return -1; } } /* ARGSUSED */ static int getFocusWindow(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; TRACE(("imlib:getFocusWindow()\n")); if (!(icp->common_attr.set_mask & ATTR_MASK_FOCUS)) { /* fill default value */ fillCommonDefault(icp, (unsigned long)ATTR_MASK_FOCUS); } if (icp->common_attr.set_mask & ATTR_MASK_FOCUS) { IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, icp->common_attr.focus); return 0; } else { /* * Couldn't get the default value. That is, neither * focus window nor client window is specified yet. */ DPRINT(("getFocusWindow without setting focus/client window previously\n")); IMCancelRequest(conn, offset); IMSendError(conn, IMBadFocusWindow, icp->im->id, icp->id, "neither of client/focus window not specified yet"); return -1; } } /* ARGSUSED */ static int getFilterEvents(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; TRACE(("imlib:getFilterEvents()\n")); /* We need only Key events */ IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, KeyPressMask | KeyReleaseMask); return 0; } /* ARGSUSED */ static int getArea(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; IMPSAttributes *ap; TRACE(("imlib:getArea()\n")); if ((ap = getPSPtr(icp, nest)) == NULL) { IMCancelRequest(conn, offset); unnestedError(icp); return -1; } if (!(ap->set_mask & ATTR_MASK_AREA)) { fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_AREA); } IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 8); /* value length */ IMPutI16(conn, ap->area.x); IMPutI16(conn, ap->area.y); IMPutC16(conn, ap->area.width); IMPutC16(conn, ap->area.height); return 0; } /* ARGSUSED */ static int getAreaNeeded(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; IMPSAttributes *ap; TRACE(("imlib:getAreaNeeded()\n")); if ((ap = getPSPtr(icp, nest)) == NULL) { IMCancelRequest(conn, offset); unnestedError(icp); return -1; } /* * Always call fillPSDefault to get appropriate AreaNeeded value. */ fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_AREA_NEEDED); TRACE(("\tarea needed: %d, %d, %d, %d\n", ap->area_needed.x, ap->area_needed.y, ap->area_needed.width, ap->area_needed.height)); IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 8); /* value length */ IMPutI16(conn, ap->area_needed.x); IMPutI16(conn, ap->area_needed.y); IMPutC16(conn, ap->area_needed.width); IMPutC16(conn, ap->area_needed.height); return 0; } /* ARGSUSED */ static int getSpotLocation(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; IMPSAttributes *ap = &icp->preedit_attr; TRACE(("imlib:getSpotLocation()\n")); if (nest == NEST_STATUS) { IMCancelRequest(conn, offset); IMSendError(conn, IMBadSomething, icp->im->id, icp->id, "spot location isn't a status attribute"); return -1; } if (!(ap->set_mask & ATTR_MASK_SPOT_LOCATION)) { fillPSDefault(icp, NEST_PREEDIT, (unsigned long)ATTR_MASK_SPOT_LOCATION); } IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutI16(conn, ap->spot_location.x); IMPutI16(conn, ap->spot_location.y); return 0; } /* ARGSUSED */ static int getColormap(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; IMPSAttributes *ap; TRACE(("imlib:getColormap()\n")); if ((ap = getPSPtr(icp, nest)) == NULL) { IMCancelRequest(conn, offset); unnestedError(icp); return -1; } if (!(ap->set_mask & ATTR_MASK_COLORMAP)) { fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_COLORMAP); } IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, ap->colormap); return 0; } /* ARGSUSED */ static int getStdColormap(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; IMPSAttributes *ap; Atom colormap_name; TRACE(("imlib:getStdColormap()\n")); if ((ap = getPSPtr(icp, nest)) == NULL) { IMCancelRequest(conn, offset); unnestedError(icp); return -1; } if (ap->set_mask & ATTR_MASK_STD_COLORMAP) { colormap_name = ap->std_colormap; } else { /* what to do? */ colormap_name = None; DPRINT(("client asks standard colormap, but not specified\n")); } IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, colormap_name); return 0; } /* ARGSUSED */ static int getForeground(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; IMPSAttributes *ap; TRACE(("imlib:getForeground()\n")); if ((ap = getPSPtr(icp, nest)) == NULL) { IMCancelRequest(conn, offset); unnestedError(icp); return -1; } if (!(ap->set_mask & ATTR_MASK_FOREGROUND)) { fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_FOREGROUND); } IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, ap->foreground); return 0; } /* ARGSUSED */ static int getBackground(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; IMPSAttributes *ap; TRACE(("imlib:getBackground()\n")); if ((ap = getPSPtr(icp, nest)) == NULL) { IMCancelRequest(conn, offset); unnestedError(icp); return -1; } if (!(ap->set_mask & ATTR_MASK_BACKGROUND)) { fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_BACKGROUND); } IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, ap->background); return 0; } /* ARGSUSED */ static int getBgPixmap(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; IMPSAttributes *ap; TRACE(("imlib:getBgPixmap()\n")); if ((ap = getPSPtr(icp, nest)) == NULL) { IMCancelRequest(conn, offset); unnestedError(icp); return -1; } if (!(ap->set_mask & ATTR_MASK_BG_PIXMAP)) { fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_BG_PIXMAP); } IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, ap->bg_pixmap); return 0; } /* ARGSUSED */ static int getFontSet(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; IMPSAttributes *ap; int name_len; TRACE(("imlib:getFontSet()\n")); if ((ap = getPSPtr(icp, nest)) == NULL) { IMCancelRequest(conn, offset); unnestedError(icp); return -1; } if (!(ap->set_mask & ATTR_MASK_FONT_SET)) { fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_FONT_SET); } name_len = strlen(ap->font_set); IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, (unsigned int)name_len); /* value length */ IMPutString(conn, ap->font_set, name_len); IMPutPad(conn); return 0; } /* ARGSUSED */ static int getLineSpace(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; IMPSAttributes *ap; TRACE(("imlib:getLineSpace()\n")); if ((ap = getPSPtr(icp, nest)) == NULL) { IMCancelRequest(conn, offset); unnestedError(icp); return -1; } if (!(ap->set_mask & ATTR_MASK_LINESPACE)) { fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_LINESPACE); } IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, (unsigned long)ap->line_space); return 0; } /* ARGSUSED */ static int getCursor(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; IMPSAttributes *ap; TRACE(("imlib:getCursor()\n")); if ((ap = getPSPtr(icp, nest)) == NULL) { IMCancelRequest(conn, offset); unnestedError(icp); return -1; } if (!(ap->set_mask & ATTR_MASK_CURSOR)) { fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_CURSOR); } IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, ap->cursor); return 0; } /* ARGSUSED */ static int getPreeditState(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; TRACE(("imlib:getPreeditState()\n")); if (nest == NEST_STATUS) { IMCancelRequest(conn, offset); IMSendError(conn, IMBadSomething, icp->im->id, icp->id, "preedit state isn't a status attribute"); return -1; } IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, (icp->state & IC_CONVERTING) ? XIMPreeditEnable : XIMPreeditDisable); return 0; } /* ARGSUSED */ static int getResetState(icp, id, nest, offset, data, len) IMIC *icp; unsigned int id; int nest; int offset; char *data; int len; { IMConnection *conn = icp->im->connection; TRACE(("imlib:getResetState()\n")); IMPutC16(conn, id); /* attribute ID */ IMPutC16(conn, 4); /* value length */ IMPutC32(conn, icp->common_attr.reset_state); return 0; } static void changeFonts(icp, preedit) IMIC *icp; int preedit; { FontBank bank = IMFontBank(icp->im); String font_set; XFontStruct ***fontsp; int *num_fontsp; TRACE(("imlib:changeFonts()\n")); if (preedit) { font_set = icp->preedit_attr.font_set; fontsp = &icp->fonts; num_fontsp = &icp->num_fonts; } else { font_set = icp->status_attr.font_set; fontsp = &icp->status_fonts; num_fontsp = &icp->num_status_fonts; } /* * Unload previous fonts. */ if (*num_fontsp > 0) { FontBankFreeFonts(bank, *fontsp, *num_fontsp); } /* * Load new fonts and store them in the IC structure. */ *fontsp = FontBankGet(bank, font_set, num_fontsp); } /* * Functions computing default attribute values */ static void fillCommonDefault(icp, mask) IMIC *icp; unsigned long mask; { IMCommonAttributes *ap = &icp->common_attr; TRACE(("imlib:fillCommonDefault()\n")); /* * Don't bother with the attributes which have been set. */ mask &= ~ap->set_mask; /* * The attributes that have default value are FocusWindow, * PreeditState and ResetState. */ if (mask & ATTR_MASK_FOCUS) { /* if ClientWindow is not set... no way */ if (mask & ATTR_MASK_CLIENT) { ap->focus = ap->client; ap->set_mask |= ATTR_MASK_FOCUS; icp->focus_profile = icp->client_profile; TRACE(("\tdefault focus window: %08lx\n", ap->focus)); } } if (mask & ATTR_MASK_PREEDIT_STATE) { /* unless the client specified, we should start with disabled state. */ ap->set_mask |= ATTR_MASK_PREEDIT_STATE; ap->reset_state = XIMPreeditDisable; } if (mask & ATTR_MASK_RESET_STATE) { /* the default reset state must be the initial state. */ ap->set_mask |= ATTR_MASK_RESET_STATE; ap->reset_state = XIMInitialState; } } static int getNaturalLineSpace(icp, preedit) IMIC *icp; int preedit; { XFontStruct **fonts; int num_fonts; int max_ascent = 0, max_descent = 0; int i; changeFonts(icp, preedit); if (preedit) { fonts = icp->fonts; num_fonts = icp->num_fonts; } else { fonts = icp->status_fonts; num_fonts = icp->num_status_fonts; } for (i = 0; i < num_fonts; i++) { XFontStruct *font = fonts[i]; if (max_ascent < font->ascent) max_ascent = font->ascent; if (max_descent < font->descent) max_descent = font->descent; } if (max_ascent + max_descent < MIN_LINE_SPACING) { return MIN_LINE_SPACING; } else { return max_ascent + max_descent; } } static void fillPSDefault(icp, type, mask) IMIC *icp; int type; /* NEST_PREEDIT or NEST_STATUS */ unsigned long mask; { IMPSAttributes *ap; IMConnection *conn = icp->im->connection; Widget pw = conn->proto_widget; int preedit; #ifdef DEBUG char *typename = (type == NEST_PREEDIT) ? "preedit" : "status"; #endif TRACE(("imlib:fillPSDefault(%s)\n", typename)); preedit = (type == NEST_PREEDIT); ap = preedit ? &icp->preedit_attr : &icp->status_attr; /* * Don't bother with the attributes which have been set. * But area_needed needs to be computed each time (to get * correct X and Y coordinates). */ mask &= ~ap->set_mask | ATTR_MASK_AREA_NEEDED; if (mask & ATTR_MASK_AREA) { computeAreaForQuery(icp); ap->set_mask |= ATTR_MASK_AREA; DDPRINT(5, ("\tdefault %s area: %d,%d,%d,%d\n", typename, ap->area.x, ap->area.y, ap->area.width, ap->area.height)); } if (mask & ATTR_MASK_FOREGROUND) { ap->foreground = IMDefaultForeground(pw); ap->set_mask |= ATTR_MASK_FOREGROUND; DDPRINT(5, ("\tdefault %s foreground: %ld\n", typename, ap->foreground)); } if (mask & ATTR_MASK_BACKGROUND) { ap->background = IMDefaultBackground(pw); ap->set_mask |= ATTR_MASK_BACKGROUND; DDPRINT(5, ("\tdefault %s background: %ld\n", typename, ap->background)); } if (mask & ATTR_MASK_COLORMAP) { ap->colormap = pw->core.colormap; ap->set_mask |= ATTR_MASK_COLORMAP; DDPRINT(5, ("\tdefault %s colormap: %08lx\n", typename, ap->colormap)); } if (mask & ATTR_MASK_STD_COLORMAP) { /* you can't fill default. what to do? */ DDPRINT(5, ("\tdefault %s std colormap: N/A\n", typename)); } if (mask & ATTR_MASK_BG_PIXMAP) { ap->bg_pixmap = None; ap->set_mask |= ATTR_MASK_BG_PIXMAP; DDPRINT(5, ("\tdefault %s background pixmap: None\n", typename)); } if (mask & ATTR_MASK_LINESPACE) { if (!(ap->set_mask & ATTR_MASK_FONT_SET)) { fillPSDefault(icp, type, (unsigned long)ATTR_MASK_FONT_SET); } ap->line_space = getNaturalLineSpace(icp, type == NEST_PREEDIT); ap->set_mask |= ATTR_MASK_LINESPACE; DDPRINT(5, ("\tdefault line space: %d\n", ap->line_space)); } if (mask & ATTR_MASK_CURSOR) { ap->cursor = None; ap->set_mask |= ATTR_MASK_CURSOR; DDPRINT(5, ("\tdefault %s cursor: None\n", typename)); } if (mask & ATTR_MASK_AREA_NEEDED) { computeAreaNeeded(icp); DDPRINT(5, ("\t%s area_needed: %d,%d,%d,%d\n", typename, ap->area_needed.x, ap->area_needed.y, ap->area_needed.width, ap->area_needed.height)); } if (mask & ATTR_MASK_FONT_SET) { ap->font_set = IMDefaultFontSet(icp->im); ap->set_mask |= ATTR_MASK_FONT_SET; DDPRINT(5, ("\tdefault %s fontset: %s\n", typename, ap->font_set)); } if (mask & ATTR_MASK_SPOT_LOCATION) { ap->spot_location.x = ap->spot_location.y = 0; ap->set_mask |= ATTR_MASK_SPOT_LOCATION; DDPRINT(5, ("\tdefault spot location: %d, %d\n", ap->spot_location.x, ap->spot_location.y)); } } /* * Function validating attribute values */ static int validateCommonAttr(icp, checkonly) IMIC *icp; int checkonly; { IMCommonAttributes *ap = &icp->common_attr; IMConnection *conn = icp->im->connection; unsigned long mask = ap->change_mask; int ret = 0; TRACE(("imlib:validateCommonAttr()\n")); mask &= ap->set_mask; #define SENDERROR(code, msg) \ if (!checkonly && ret == 0) { \ IMSendError(conn, code, icp->im->id, icp->id, msg); ret = -1; \ } if (mask & ATTR_MASK_INPUT_STYLE) { XIMStyle xstyle = icp->common_attr.input_style; InputStyle *isp = styles; while (isp->xim_style != 0) { if (isp->xim_style == xstyle) break; isp++; } if (isp->xim_style == 0) { DPRINT(("unsupported input style\n")); ap->set_mask &= ~ATTR_MASK_INPUT_STYLE; SENDERROR(IMBadStyle, "unsupported input style"); } else { icp->style = isp->conversion_style; } } if (mask & ATTR_MASK_CLIENT) { if (!validateClientWindow(icp)) { DPRINT(("invalid client window ID\n")); ap->set_mask &= ~ATTR_MASK_CLIENT; SENDERROR(IMBadClientWindow, "invalid client window ID"); } } if (mask & ATTR_MASK_FOCUS) { if (!validateFocusWindow(icp)) { DPRINT(("invalid focus window ID\n")); ap->set_mask &= ~ATTR_MASK_FOCUS; SENDERROR(IMBadFocusWindow, "invalid focus window ID"); } } if (mask & ATTR_MASK_PREEDIT_STATE) { unsigned long preedit_state = ap->preedit_state; if (preedit_state != XIMPreeditEnable && preedit_state != XIMPreeditDisable) { DPRINT(("invalid preedit state\n")); ap->set_mask &= ~ATTR_MASK_PREEDIT_STATE; SENDERROR(IMBadSomething, "invalid preedit state"); } } if (mask & ATTR_MASK_RESET_STATE) { unsigned long reset_state = ap->reset_state; if (reset_state != XIMInitialState && reset_state != XIMPreserveState) { /* * Xlib document says invalid values should be interpreted as * XIMInitialState. */ DPRINT(("invalid reset state -- forcing initial state\n")); ap->reset_state = XIMInitialState; } } return ret; #undef SENDERROR } static int validatePSAttr(icp, type, checkonly) IMIC *icp; int type; int checkonly; { /* * Check validity of preedit/status attribute values. * 'type' is either NEST_PREEDIT or NEST_STATUS, indicating * whether preedit or status attributes are to be checked. * 'mask' is the attribute mask to be checked. * If all the attributes are valid, this function return 0. * Otherwise it issues an error message for the first invalid * value detected, and returns -1. */ IMPSAttributes *ap; IMConnection *conn = icp->im->connection; unsigned long mask; int preedit; int ret = 0; TRACE(("imlib:validatePSAttr()\n")); preedit = (type == NEST_PREEDIT); ap = preedit ? &icp->preedit_attr : &icp->status_attr; /* do not check unset attributes */ mask = ap->change_mask & ap->set_mask; #define SENDERROR(code, msg) \ if (!checkonly && ret == 0) { \ IMSendError(conn, code, icp->im->id, icp->id, msg); ret = -1; \ } if (mask & ATTR_MASK_AREA) { if (ap->area.width == 0 || ap->area.height == 0) { ap->set_mask &= ~ATTR_MASK_AREA; DPRINT(("zero area width/height\n")); SENDERROR(IMBadArea, "invalid area width/height"); } } #ifdef notdef if (mask & ATTR_MASK_COLORMAP) { } if (mask & ATTR_MASK_BG_PIXMAP) { } #endif if (mask & ATTR_MASK_LINESPACE) { if (ap->line_space < MIN_LINE_SPACING) { ap->set_mask &= ~ATTR_MASK_LINESPACE; /* * we don't send error message in this case, because * there exist some applications which send invalid line * spacing and we don't want to break them. */ DPRINT(("line space too small %d\n", ap->line_space)); } } #ifdef notdef if (mask & ATTR_MASK_CURSOR) { /* How should we check it? */ } #endif if (mask & ATTR_MASK_AREA_NEEDED) { } #ifdef notdef if (mask & ATTR_MASK_FONT_SET) { } if (mask & ATTR_MASK_SPOT_LOCATION) { } #endif return ret; #undef SENDERROR } /* * Functions to extract necessary attributes and make conversion argument */ static void changeConversionAttributes(icp) IMIC *icp; { unsigned long mask; ConversionAttributes attr; TRACE(("imlib:changeConversionAttributes()\n")); mask = IMMakeConvAttributes(icp, &attr); CControlChangeAttributes(icp->conversion, mask, &attr); } static void computeAreaNeeded(icp) IMIC *icp; { IMPSAttributes *pattr = &icp->preedit_attr; IMPSAttributes *sattr = &icp->status_attr; IMWindowProfile *cpr = &icp->client_profile; int width, height; int min_width, min_height; int default_status_width; int font_height; TRACE(("computeAreaNeeded()\n")); if (icp->style == IMSTYLE_SEPARATE) return; /* * Get the current dimension of the client window. */ (void)validateClientWindow(icp); /* * Compute the dimensions of the status region. */ fillPSDefault(icp, NEST_STATUS, (unsigned long)ATTR_MASK_LINESPACE); font_height = sattr->line_space + 2; width = height = 0; if (sattr->set_mask & ATTR_MASK_AREA_NEEDED) { width = sattr->area_needed.width; height = sattr->area_needed.height; TRACE(("\tstatus areaNeeded was: (%d,%d)\n", width, height)); } min_width = font_height * 3; min_height = font_height; if (min_width < MIN_AREA_WIDTH) min_width = MIN_AREA_WIDTH; if (min_height < MIN_AREA_HEIGHT) min_height = MIN_AREA_HEIGHT; if (width == 0) { default_status_width = IMStatusWidth(icp->im->connection->proto_widget); if (default_status_width > 0) { width = default_status_width; } else { width = cpr->width / 5; /* wild guess */ } } if (width < min_width) width = min_width; if (height < min_height) height = min_height; sattr->area_needed.x = 0; sattr->area_needed.y = cpr->height - height; sattr->area_needed.width = width; sattr->area_needed.height = height; TRACE(("\tstatus areaNeeded is now: (%d, %d, %d, %d)\n", sattr->area_needed.x, sattr->area_needed.y, width, height)); /* * Compute the dimensions of the pre-edit region. */ if (icp->style != IMSTYLE_OFF_THE_SPOT) return; fillPSDefault(icp, NEST_PREEDIT, (unsigned long)ATTR_MASK_LINESPACE); font_height = pattr->line_space + 2; width = height = 0; if (pattr->set_mask & ATTR_MASK_AREA_NEEDED) { width = pattr->area_needed.width; height = pattr->area_needed.height; TRACE(("\tpreedit areaNeeded was: (%d,%d)\n", width, height)); } min_width = (cpr->width - sattr->area_needed.width) / 2; min_height = font_height; if (min_width < MIN_AREA_WIDTH) min_width = MIN_AREA_WIDTH; if (min_height < MIN_AREA_HEIGHT) min_height = MIN_AREA_HEIGHT; if (width < min_width) width = min_width; if (height < min_height) height = min_height; pattr->area_needed.x = sattr->area_needed.width; pattr->area_needed.y = cpr->height - height; pattr->area_needed.width = width; pattr->area_needed.height = height; TRACE(("\tpreedit areaNeeded is now: (%d, %d, %d, %d)\n", pattr->area_needed.x, pattr->area_needed.y, width, height)); } static void computeAreaForQuery(icp) IMIC *icp; { IMPSAttributes *pattr = &icp->preedit_attr; IMPSAttributes *sattr = &icp->status_attr; TRACE(("computeAreaForQuery()\n")); if (icp->style == IMSTYLE_SEPARATE) return; computeAreaNeeded(icp); if (!(pattr->set_mask & ATTR_MASK_AREA)) { if (icp->style == IMSTYLE_OVER_THE_SPOT) { IMWindowProfile *fpr = &icp->focus_profile; pattr->area.x = 0; pattr->area.y = 0; pattr->area.width = fpr->width; pattr->area.height = fpr->height; } else { /* IMSTYLE_OFF_THE_SPOT */ pattr->area = pattr->area_needed; } } if (!(sattr->set_mask & ATTR_MASK_AREA)) { sattr->area = sattr->area_needed; } } /* * Public functions */ /*- IMPutIMAttrList: write list of supported IM attributes to output buffer -*/ void IMPutIMAttrList(imp) IMIM *imp; { IMConnection *conn = imp->connection; IMAttribute *iap; int offset, list_start, list_end; int n; TRACE(("IMPutIMAttrList()\n")); offset = IMWritePos(conn); IMPutC16(conn, 0); /* dummy. overwritten afterwards */ list_start = IMWritePos(conn); for (n = 0, iap = imAttributes; n < numImAttributes; n++, iap++) { int length; IMPutC16(conn, (unsigned int)n); IMPutC16(conn, (unsigned int)iap->type); length = strlen(iap->name); IMPutC16(conn, (unsigned int)length); IMPutString(conn, iap->name, length); IMPutPad(conn); } list_end = IMWritePos(conn); IMRewriteC16(conn, offset, (unsigned int)(list_end - list_start)); } /*- IMPutICAttrList: write list of supported IC attributes to output buffer -*/ void IMPutICAttrList(imp) IMIM *imp; { IMConnection *conn = imp->connection; ICAttribute *iap; int offset, list_start, list_end; int n; TRACE(("IMPutICAttrList()\n")); offset = IMWritePos(conn); IMPutC16(conn, 0); /* dummy. overwritten afterwards */ IMPutC16(conn, 0); /* unused */ list_start = IMWritePos(conn); for (n = 0, iap = icAttributes; n < numIcAttributes; n++, iap++) { int length; IMPutC16(conn, (unsigned int)n); IMPutC16(conn, (unsigned int)iap->type); length = strlen(iap->name); IMPutC16(conn, (unsigned int)length); IMPutString(conn, iap->name, length); IMPutPad(conn); } list_end = IMWritePos(conn); IMRewriteC16(conn, offset, (unsigned int)(list_end - list_start)); } /* ARGSUSED */ int IMSetIMValues(imp, data, len, major) IMIM *imp; char *data; int len; int major; { TRACE(("IMSetIMValues(): not supported yet\n")); /* not supported yet */ IMSendError(imp->connection, IMBadProtocol, imp->id, 0, "this protocol is not supported yet"); return -1; } int IMGetIMValues(imp, data, len, offset) IMIM *imp; char *data; int len; int offset; /* request offset */ { IMConnection *conn = imp->connection; int pos, list_start, list_end; TRACE(("IMGetIMValues()\n")); pos = IMWritePos(conn); IMPutC16(conn, 0); /* length of the list. to be overwritten. */ list_start = IMWritePos(conn); if (getIMValues(imp, data, len, offset) < 0) return -1; list_end = IMWritePos(conn); IMRewriteC16(conn, pos, (unsigned int)(list_end - list_start)); return 0; } int IMSetICValues(icp, data, len, major) IMIC *icp; char *data; int len; int major; { int r1, r2, r3; TRACE(("IMSetICValues()\n")); /* clear change mask */ icp->common_attr.change_mask = 0; icp->preedit_attr.change_mask = 0; icp->status_attr.change_mask = 0; /* read the specified data and set attributes */ r1 = setICValues(icp, data, len, 0, (major == XIM_CREATE_IC) ? OP_C : OP_S); /* validate attributes */ r2 = IMValidateICAttributes(icp, (r1 < 0)); /* * If the operation is CREATE_IC, input style attribute must be set. */ if (major == XIM_CREATE_IC && !(icp->common_attr.set_mask & ATTR_MASK_INPUT_STYLE) && r1 == 0 && r2 == 0) { DPRINT(("input style not specified by CreateIC\n")); IMSendError(icp->im->connection, IMBadSomething, icp->im->id, icp->id, "inputStyle resource must be set"); r3 = -1; } else { r3 = 0; } if (r1 == 0 && r2 == 0) { /* if conversion is taking place... */ if (icp->state & IC_CONVERTING) { changeConversionAttributes(icp); } /* if preedit state is specified... */ if (icp->common_attr.change_mask & ATTR_MASK_PREEDIT_STATE) { TRACE(("changing preedit state to %s\n", (icp->common_attr.preedit_state == XIMPreeditEnable) ? "enabled" : "disabled")); if (icp->common_attr.preedit_state == XIMPreeditEnable) { IMStartConversion(icp); } else { IMStopConversion(icp); } } } return (r1 < 0 || r2 < 0 || r3 < 0) ? -1 : 0; } int IMGetICValues(icp, data, len, offset) IMIC *icp; char *data; int len; int offset; /* request offset */ { int nested_separator; int r; IMConnection *conn = icp->im->connection; int pos, list_start, list_end; TRACE(("IMGetICValues()\n")); pos = IMWritePos(conn); IMPutC16(conn, 0); /* dummy. overwritten afterwards */ IMPutC16(conn, 0); /* unused */ list_start = IMWritePos(conn); r = getICValues(icp, data, len, NEST_NONE, offset, &nested_separator); if (r < 0) return -1; list_end = IMWritePos(conn); IMRewriteC16(conn, pos, (unsigned int)(list_end - list_start)); if (nested_separator) { /* * There must have been some unbalanced NestedListSeparator. */ DPRINT(("getICvalues: unmatched separator\n")); IMCancelRequest(icp->im->connection, offset); IMSendError(icp->im->connection, IMBadSomething, icp->im->id, icp->id, "corrupted nested list"); return -1; } return 0; } void IMFillDefault(icp, common_mask, preedit_mask, status_mask) IMIC *icp; unsigned long common_mask; unsigned long preedit_mask; unsigned long status_mask; { TRACE(("IMFillDefault()\n")); if (common_mask != 0) fillCommonDefault(icp, common_mask); if (preedit_mask != 0) fillPSDefault(icp, NEST_PREEDIT, preedit_mask); if (status_mask != 0) fillPSDefault(icp, NEST_STATUS, status_mask); } int IMValidateWindow(dpy, win, profilep) Display *dpy; Window win; IMWindowProfile *profilep; { Window root; int x, y; unsigned int width, height, border, depth; XAEHandle h; int s; TRACE(("IMValidateWindow(win: %08lx)\n", win)); h = XAESetIgnoreErrors(dpy); s = XGetGeometry(dpy, win, &root, &x, &y, &width, &height, &border, &depth); XAEUnset(h); if (profilep != NULL && s) { profilep->width = width; profilep->height = width; profilep->root = root; } return s; } int IMValidateICAttributes(icp, checkonly) IMIC *icp; int checkonly; { int error_occured; int r; TRACE(("IMValidateICAttributes()\n")); /* * Be careful not to send multiple error messages. */ error_occured = 0; r = validateCommonAttr(icp, checkonly); if (r < 0) error_occured = 1; r = validatePSAttr(icp, NEST_PREEDIT, (checkonly && error_occured)); if (r < 0) error_occured = 1; r = validatePSAttr(icp, NEST_STATUS, (checkonly && error_occured)); if (r < 0) error_occured = 1; return error_occured ? -1 : 0; } void IMFreeICAttributes(icp) IMIC *icp; { IMPSAttributes *pattr = &icp->preedit_attr; IMPSAttributes *sattr = &icp->status_attr; FontBank bank = IMFontBank(icp->im); TRACE(("IMFreeICAttributes()\n")); if (pattr->set_mask & ATTR_MASK_FONT_SET) XtFree(pattr->font_set); if (sattr->set_mask & ATTR_MASK_FONT_SET) XtFree(sattr->font_set); if (icp->num_fonts > 0) { FontBankFreeFonts(bank, icp->fonts, icp->num_fonts); } if (icp->num_status_fonts > 0) { FontBankFreeFonts(bank, icp->status_fonts, icp->num_status_fonts); } } unsigned long IMMakeConvAttributes(icp, attr) IMIC *icp; ConversionAttributes *attr; { IMCommonAttributes *cattr; IMPSAttributes *pattr, *sattr; unsigned long cmask; /* changed attributes */ unsigned long mask; /* attributes to be set */ TRACE(("IMMakeConvAttributes()\n")); mask = 0L; cattr = &icp->common_attr; pattr = &icp->preedit_attr; sattr = &icp->status_attr; /* * Check changes of common attributes. */ cmask = cattr->change_mask; /* focus window */ if (cmask & ATTR_MASK_FOCUS) { attr->focuswindow = cattr->focus; mask |= CAFocusWindow; } /* * Check changes of preedit attributes. */ cmask = pattr->change_mask; /* client area */ if (cmask & ATTR_MASK_AREA) { attr->clientarea.x = pattr->area.x; attr->clientarea.y = pattr->area.y; attr->clientarea.width = pattr->area.width; attr->clientarea.height = pattr->area.height; mask |= CAClientArea; } /* foreground/background */ if (cmask & ATTR_MASK_FOREGROUND) { attr->foreground = pattr->foreground; mask |= CAColor; } if (cmask & ATTR_MASK_BACKGROUND) { attr->background = pattr->background; mask |= CAColor; } /* colormap */ if (cmask & ATTR_MASK_COLORMAP) { attr->colormap = pattr->colormap; mask |= CAColormap; } /* background pixmap */ if (cmask & ATTR_MASK_BG_PIXMAP) { attr->background_pixmap = pattr->bg_pixmap; mask |= CABackgroundPixmap; } /* line spacing */ if (cmask & ATTR_MASK_LINESPACE) { attr->linespacing = pattr->line_space; mask |= CALineSpacing; } /* cursor */ if (cmask & ATTR_MASK_CURSOR) { attr->cursor = pattr->cursor; mask |= CACursor; } /* font */ if (cmask & ATTR_MASK_FONT_SET) { changeFonts(icp, 1); attr->fonts = icp->fonts; attr->num_fonts = icp->num_fonts; mask |= CAFonts; } /* spot location */ if ((cmask & ATTR_MASK_SPOT_LOCATION) && icp->style == IMSTYLE_OVER_THE_SPOT) { attr->spotx = pattr->spot_location.x; attr->spoty = pattr->spot_location.y; mask |= CASpotLocation; } /* * Check changes of status attributes. */ cmask = sattr->change_mask; /* status area */ if (cmask & ATTR_MASK_AREA) { attr->statusarea.x = sattr->area.x; attr->statusarea.y = sattr->area.y; attr->statusarea.width = sattr->area.width; attr->statusarea.height = sattr->area.height; mask |= CAStatusArea; } /* font */ if (cmask & ATTR_MASK_FONT_SET) { changeFonts(icp, 0); attr->status_fonts = icp->status_fonts; attr->num_status_fonts = icp->num_status_fonts; mask |= CAStatusFonts; } return mask; } void IMMoveLocation(icp, x, y) IMIC *icp; int x; int y; { TRACE(("IMMoveLocation()\n")); icp->preedit_attr.spot_location.x = x; icp->preedit_attr.spot_location.y = y; icp->preedit_attr.set_mask |= ATTR_MASK_SPOT_LOCATION; icp->preedit_attr.change_mask = ATTR_MASK_SPOT_LOCATION; if (icp->state & IC_CONVERTING) { changeConversionAttributes(icp); } }