/* ### ### This file is part of ### ### TurboLinux ZWinPro ### ### Copyright (C) 1999-2000 TurboLinux, Inc. ### All Rights Reserved ### Distributed under the terms of the GNU General Public License (GPL) ### ### ### Authors: TurboLinux Chinese Development Team: ### Justin Yu ### Sean Chen ### Daniel Fang ### */ //OffTheSpot implementation //Tested for rxvt //OffTheSpot is a bit tricky, by usual, the applications provide //the status area and preedit area, the IM server will display //status of current IM and preedit string and candidate list. //but the application often has problem in drawing into other //applications' window //To start rxvt in off-the-spot style, please type in // rxvt -fn 8x16 -im Chinput -km gb(big5) -pt OffTheSpot //Here I use the reparent method to embed the status and preedit //window into the application. For every IC, if it is the offspot //input style, these two windows are created.(If use two common windows, //the windows maybe crashed if the application exit abnormally). //For qt/kde applications, the specified offthespot areas has problem //It should be specified by the IM server. To invoke this mode, //please set the resource file /usr/lib/ZWinPro/Chinput.ad or //~/.chinput to //chinput.areamode = SERVER //In such case, Chinput will try to find the top window of the application //and reparent the preedit and status window to the lower-bottom //of application's window. // //To start qt/kde apps in offthespot style, please add command line //parameters "-inputstyle offthespot", the default style is overthespot. //e.g. // kedit -inputstyle offthespot // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //FIXME //For qt-1.44/kde-1.x applications, chinput.areamode should be set to SERVER //mode. #include "all.h" #define max(a, b) ((a) > (b) ? (a) : (b)) static int preedit_width = 0; void HZoffspotReparentWindows(IC *ic) { //put the status and preedit window in the //client window... if(flag_client == HZSERVER_AREAMODE_CLIENT){ //reparent according to client settings if(ic->client_win){ XReparentWindow(display, ic->status_win, ic->client_win, ic->sts_attr.area.x, ic->sts_attr.area.y); XReparentWindow(display, ic->preedit_win,ic->client_win, ic->pre_attr.area.x, //ic->sts_attr.area.x + ic->sts_attr.area.width, ic->pre_attr.area.y); } } else { XWindowAttributes xwa; Window win; win = find_top_window(ic->client_win); if(!win) return; XGetWindowAttributes(display, win, &xwa); //reparent in the top window by IM server. XReparentWindow(display, ic->status_win, win, 0, xwa.height - FONT_HEIGHT); XReparentWindow(display, ic->preedit_win, win, AREA_CHARS * FONT_WIDTH / 2, xwa.height - FONT_HEIGHT); } } void HZoffspotMapWindows() { IC *ic = (IC *)FindIC(last_icid); if(!ic) return; XMapRaised(display, ic->status_win); XMapRaised(display, ic->preedit_win); } void HZoffspotMoveResizeWindows(IC *ic) { if(flag_client == HZSERVER_AREAMODE_CLIENT){ XMoveResizeWindow(display, ic->status_win, ic->sts_attr.area.x, ic->sts_attr.area.y, max(ic->sts_attr.area.width, ic->sts_attr.area_needed.width), ic->sts_attr.area.height); XMoveResizeWindow(display, ic->preedit_win, ic->pre_attr.area.x, //ic->sts_attr.area.x + max(ic->sts_attr.area.width, //ic->sts_attr.area_needed.width), ic->pre_attr.area.y, max(ic->pre_attr.area.width, ic->pre_attr.area_needed.width), ic->pre_attr.area.height); } else { //The server will process the area window position //finding the geometry of the top window and reparent //the area windows in the lower left corner //The area will be 16 pixel in height and fill out //the bottom line of the top window. //get position in realtime XWindowAttributes xwa; Window win; win = find_top_window(ic->client_win); if(!win) return; XGetWindowAttributes(display, win, &xwa); //record preedit_width = xwa.width - AREA_CHARS * FONT_WIDTH / 2; XMoveResizeWindow(display, ic->status_win, 0, xwa.height - FONT_HEIGHT, AREA_CHARS * FONT_WIDTH / 2, FONT_HEIGHT); XMoveResizeWindow(display, ic->preedit_win, AREA_CHARS * FONT_WIDTH / 2, xwa.height - FONT_HEIGHT, xwa.width - AREA_CHARS * FONT_WIDTH / 2, FONT_HEIGHT); } } void HZoffspotHideWindows() { IC *ic = (IC *)FindIC(last_icid); if(!ic) return; XUnmapWindow(display, ic->status_win); XUnmapWindow(display, ic->preedit_win); } void HZoffspotHideStatusWindow(IC *ic) { if(!ic) return; XUnmapWindow(display, ic->status_win); } void HZoffspotPreeditDraw(char *s, int len, int pos) { IC *ic = (IC *)FindIC(last_icid); if(!ic) return; //clear the preedit area if(flag_client == HZSERVER_AREAMODE_CLIENT) XFillRectangle(display, ic->preedit_win, offspot_bggc, 0, 0, max(ic->pre_attr.area.width, ic->pre_attr.area_needed.width), ic->pre_attr.area.height); else if(flag_client == HZSERVER_AREAMODE_SERVER) XFillRectangle(display, ic->preedit_win, offspot_bggc, 0, 0, preedit_width, FONT_HEIGHT); //draw the string in the preedit area //MyDrawString(ic->preedit_win, HZServer.lightGC, 0, FONT_ASCENT, s, len); MyDrawString2(ic->preedit_win, offspot_gc, offspot_gbgc, offspot_big5gc, 0, FONT_ASCENT, s, len); HZoffspotDrawCaret(ic, pos); } //draw small triangle for caret position void HZoffspotDrawCaret(IC *ic, int pos) { //draw the caret int caretx = pos * 8; int carety = FONT_ASCENT; XPoint point[3]; point[0].x = caretx + 4; point[0].y = carety - 4; point[1].x = point[0].x - 4; point[1].y = carety + 1; point[2].x = point[0].x + 4; point[2].y = carety + 1; //MyDrawString2(ic->preedit_win,offspot_gc,offspot_gbgc,offspot_big5gc, //caretx, carety, "|", 1); XFillPolygon(display, ic->preedit_win, offspot_gc, point, 3, Convex, CoordModeOrigin); } void HZoffspotStatusDraw() { char buf[128]; IC *ic = (IC *)FindIC(last_icid); if(!ic) return; //only status area style supported if(!(ic->input_style & XIMStatusArea)) return; HZoffspotMoveResizeWindows(ic); if(ic->reparented){ HZoffspotMapWindows(); } else { //if not reparented, init all first HZoffspotReparentWindows(ic); HZoffspotMapWindows(); ic->reparented = 1; } //clear status area if(flag_client == HZSERVER_AREAMODE_CLIENT) XFillRectangle(display, ic->status_win, offspot_bggc, 0, 0, max(ic->sts_attr.area.width, ic->sts_attr.area_needed.width), ic->sts_attr.area.height); else if(flag_client == HZSERVER_AREAMODE_SERVER) XFillRectangle(display, ic->status_win, offspot_bggc, 0, 0, AREA_CHARS * FONT_WIDTH / 2, FONT_HEIGHT); #ifdef HAVE_LIBIMLIB Imlib_paste_image(icon_id, im_chinput, ic->status_win, 0, 0, 16, 16); #endif //draw preedit string and candidate string //in preedit window if(HZServer.encoding == HZSERVER_ENCODING_GB){ strcpy(buf, ""); if(flag_corner) strcat(buf, "¡¾È«"); else strcat(buf, "¡¾°ë"); if(flag_punct) strcat(buf, "£ï¡¿"); else strcat(buf, " .¡¿"); strcat(buf, chinputime[cur_inputmethod].namegb); strcat(buf, ": "); } else { strcpy(buf, ""); if(flag_corner) strcat(buf, "¡i¥þ"); else strcat(buf, "¡i¥b"); if(flag_punct) strcat(buf, "¡³¡j"); else strcat(buf, "¡E¡j"); strcat(buf, chinputime[cur_inputmethod].namebig5); strcat(buf, ": "); } MyDrawString2(ic->status_win, offspot_gc, offspot_gbgc, offspot_big5gc, 16, FONT_ASCENT, buf, strlen(buf)); } void HZoffspotFlush(void) { char mbuf1[256], mbuf2[256], mbuf[256]; //if(flag_refresh)return; bzero(mbuf1, 256); bzero(mbuf2, 256); //draw status area //The contents of status area contains // 1. corner mode // 2. punctuation mode // 3. input method HZoffspotStatusDraw(); if(flag_english) strcpy(mbuf1, input_buf); else IMM_GetInputDisplay (chinput_imm, mbuf1, sizeof (mbuf1)); IMM_GetSelectDisplay (chinput_imm, mbuf2, sizeof (mbuf2)); if(strlen(mbuf2) == 0) flag_found = 0; else flag_found = 1; sprintf(mbuf, "%s %s", mbuf1, mbuf2); HZoffspotPreeditDraw(mbuf, strlen(mbuf), strlen(mbuf1)); }