/* ### This file is part of HappyLinux HappyIM ### Copyright (C) 2000-2001 Legend Computer, Inc. ### Distributed under the terms of the GNU General Public License (GPL) ### Author: Yang Botao ### Modified from : */ /* ### ### Distributed under the terms of the GNU General Public License (GPL) ### Authors: TurboLinux Chinese Development Team: ### Justin Yu ### Sean Chen ### Daniel Fang ### */ //overthespot style is almost available by all XIM applications. //it contains two parts: the preedit part and the candidate part. //status area is optional for apps. //+----------------+ +------------------+ //|preedit | |[status][ime name]| //+----------------+ +------------------+ // |1. xxx | // |2. xxx | // |. | // |. | // |. | // |. | // |. | // |. | // |0. xxx | // +------------------+ // | [arrows] | // +------------------+ //This is the a caret mode implementation for root-window preedit // style of XIM, it simulates the MS Windows' Chinese input method. // Now many applications support caret mode, such as gtk/gnome based // and qt/kde based applications. rxvt, a terminal simulator, also // support such mode by modify its source slightly. // -- Justin Yu //Netscape use overthespot as the default input style, //i.e. XIMPreeditPosition | XIMStatusArea. In fact, preedit //position is enough for Chinput-2.1 and above versions. //The status area has no much use. #include "all.h" #define max(a, b) ((a) > (b) ? (a) : (b)) static int flag_noinput = 1; void HZinitServerCaretMode(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) { //init geometry of windows of input area //and candidate area HZServer.hzCwin.x1 = x1; HZServer.hzCwin.y1 = y1; HZServer.hzCwin.w1 = w1; HZServer.hzCwin.h1 = h1; HZServer.hzCwin.x2 = x2; HZServer.hzCwin.y2 = y2; HZServer.hzCwin.w2 = w2; HZServer.hzCwin.h2 = h2; //up/down arrow button HZServer.hzCwin.b1_x1 = 16; HZServer.hzCwin.b1_y1 = h2 - 16; HZServer.hzCwin.b1_x2 = 8; HZServer.hzCwin.b1_y2 = h2 - 6; HZServer.hzCwin.b1_x3 = 24; HZServer.hzCwin.b1_y3 = h2 - 6; HZServer.hzCwin.b2_x1 = 36; HZServer.hzCwin.b2_y1 = h2 - 16; HZServer.hzCwin.b2_x2 = 44; HZServer.hzCwin.b2_y2 = h2 - 6; HZServer.hzCwin.b2_x3 = 52; HZServer.hzCwin.b2_y3 = h2 - 16; HZServer.hzCwin.s_x1 = 2; HZServer.hzCwin.s_y1 = 26; HZServer.hzCwin.s_x2 = w2 - 2; HZServer.hzCwin.s_y2 = h2 - 22; } void HZoverspotHideStatusWindow(void) { IC *ic = (IC *)FindIC(last_icid); //if(dmode == HZSERVER_DMODE_OVERSPOT) XUnmapWindow(display, window2); if(!ic) return; if(!(ic->input_style & XIMStatusArea)) return; if(ic->status_win) XUnmapWindow(display, ic->status_win); } //set the location of input bar void HZoverspotSetLocation(IC *ic) { int x0, y0; Window child; int curx1, cury1, curx2, cury2; int dw = DisplayWidth(display, screen_num); int dh = DisplayHeight(display, screen_num); //for Strange xterm XsetICValues problem which setic even in unfocus window. if((current_focus_ic != NULL) && (ic != NULL)) if((CARD16 ) current_focus_ic->id != (CARD16) ic->id) return; //focus window is usually the same as client window //but in some cases, focus win is none //Note: //if the area is a scrolled area, then the location //maybe not correct. e.g., kedit with a long line being //edited. In such case, there should have a checking //for the border of window, but now for simplicity... if(ic->focus_win) { //try focus win first XTranslateCoordinates(display, ic->focus_win, DefaultRootWindow(display), ic->pre_attr.spot_location.x + HZSERVER_POS_XOFFSET, ic->pre_attr.spot_location.y + HZSERVER_POS_YOFFSET, &x0, &y0, &child); } else if(ic->client_win) { XTranslateCoordinates(display, ic->client_win, DefaultRootWindow(display), ic->pre_attr.spot_location.x + HZSERVER_POS_XOFFSET, ic->pre_attr.spot_location.y + HZSERVER_POS_YOFFSET, &x0, &y0, &child); } else { return; } //set the location of input window curx1 = x0; cury1 = y0; if(curx1 < 0) curx1 = 0; if(cury1 < 0) cury1 = 0; if(curx1 + width_input_win + 4 > dw) curx1 = dw - width_input_win - 4; if(cury1 + HZSERVER_INPUT_WIN16_HEIGHT + 4 > dh) cury1 = cury1 - HZSERVER_INPUT_WIN16_HEIGHT - 40; if(cury1 + HZSERVER_INPUT_WIN16_HEIGHT + 4 > dh) cury1 = dh - HZSERVER_INPUT_WIN16_HEIGHT - 4; XMoveWindow(display, HZServer.window1, curx1, cury1); XRaiseWindow(display, HZServer.window1); if(HZServer.hzVKwin.onflag) XRaiseWindow(display, HZServer.window3); //set location of candidate window curx2 = curx1 + width_input_win + 4; cury2 = cury1; if(curx2 < curx1 + width_input_win + 4) curx2 = curx1 + width_input_win + 4; if(curx2 + HZSERVER_CHOICE_WIN16_WIDTH + 4 > dw) curx2 = curx1 - HZSERVER_CHOICE_WIN16_WIDTH - 4; if(cury2 < 0) cury2 = 0; if(cury2 + HZSERVER_CHOICE_WIN16_HEIGHT + 4 > dh) cury2 = dh - HZSERVER_CHOICE_WIN16_HEIGHT - 4; //record position HZServer.hzCwin.x2 = curx2; HZServer.hzCwin.y2 = cury2; XMoveWindow(display, HZServer.window2, curx2, cury2); XRaiseWindow(display, HZServer.window2); //save the position HZServer.hzIwin.x = curx1; HZServer.hzIwin.y = cury1; } void HZoverspotResizeWindow(char *buf,int len) { int curx1, cury1, curx2, cury2,i,tmplen; int dw = DisplayWidth(display, screen_num); int dh = DisplayHeight(display, screen_num); tmplen=mb_strwidth(buf,len); // if(tmplen < HZSERVER_INPUT_CHARS) // tmplen = HZSERVER_INPUT_CHARS; width_input_win = tmplen * 8 + 26; //get the position of window //and move window2 first curx1 = HZServer.hzIwin.x; cury1 = HZServer.hzIwin.y; if(curx1 + width_input_win + 4 > dw) curx1 = dw - width_input_win - 4; if(cury1 + HZSERVER_INPUT_WIN16_HEIGHT + 4 > dh) cury1 = dh - HZSERVER_INPUT_WIN16_HEIGHT - 4; //move candidate window first, //IF we resize input window first, the input window //may obscure the candidate window, and cause remap curx2 = curx1 + width_input_win + 4; cury2 = cury1; if(curx2 < curx1 + width_input_win + 4) curx2 = curx1 + width_input_win + 4; if(curx2 + HZSERVER_CHOICE_WIN16_WIDTH + 4 > dw) curx2 = curx1 - HZSERVER_CHOICE_WIN16_WIDTH - 4; if(cury2 < 0) cury2 = 0; if(cury2 + HZSERVER_CHOICE_WIN16_HEIGHT + 4 > dh) cury2 = dh - HZSERVER_CHOICE_WIN16_HEIGHT - 4; XMoveWindow(display, window2, curx2, cury2); XMoveWindow(display, window1, curx1, cury1); XResizeWindow(display, window1, width_input_win, HZServer.hzCwin.h1); if(map_mode == 1)XMapRaised(display, window1); } void HZoverspotDrawInputArea(char *buf, int len) { //check space for input area HZoverspotResizeWindow(buf,len); HZoverspotDrawInputPanel(); //draw the string #ifdef HAVE_LIBIMLIB if(flag_noinput == 1) MyDrawString(window1, HZServer.normalGC, 20, HZServer.f_height+3, buf, len); else MyDrawString(window1, HZServer.normalGC, 4, HZServer.f_height+3, buf, len); #else MyDrawString(window1, HZServer.normalGC, 4, HZServer.f_height+3, buf, len); #endif } void HZoverspotInputFlush(void) { char mbuf[256]; //if(flag_refresh)return; //input area bzero(mbuf, 256); if(flag_english == True) strcpy(mbuf, input_buf); else IMM_GetInputDisplay (chinput_imm, mbuf, sizeof (mbuf)); flag_noinput = 0; if(strlen(mbuf) == 0 && flag_showime == 1){ flag_noinput = 1; if(HZServer.encoding == HZSERVER_ENCODING_GB) sprintf(mbuf, "%s", chinputime[cur_inputmethod].namegb); /* else if(HZServer.encoding == HZSERVER_ENCODING_JIS) sprintf(mbuf, "%s_", chinputime[cur_inputmethod].namejis); else if(HZServer.encoding == HZSERVER_ENCODING_KSC) sprintf(mbuf, "%s_", chinputime[cur_inputmethod].nameksc); */ else sprintf(mbuf, "%s", chinputime[cur_inputmethod].namebig5); } HZoverspotDrawInputArea(mbuf, strlen(mbuf)); } void mark_item(int item) { int y; y = HZServer.f_height + 28 + (item-1) * (HZServer.f_height + 2) - 17; XDrawRectangle(display, window2, HZServer.dimGC, 5, y, HZServer.hzCwin.w2-11, 17); } void unmark_item(int item) { int y; if(item == -1) return; y = HZServer.f_height + 28 + (item-1) * (HZServer.f_height + 2) - 17; XDrawRectangle(display, window2, HZServer.panelGC, 5, y, HZServer.hzCwin.w2-11, 17); } void HZprocCandidateWindow(int x0, int y0) { int item; static int pre_item = -1; //get last motion if(dmode != HZSERVER_DMODE_OVERSPOT && dmode != HZSERVER_DMODE_ONSPOT) return; if(x0 < 6 || x0 > HZServer.hzCwin.s_x2-5 || y0 < 26 || y0 > HZServer.hzCwin.h2-22) { unmark_item(pre_item); pre_item = -1; return; } //item from 1 to 10 if within the area item = (y0 - HZServer.hzCwin.s_y1) / (HZServer.f_height + 2) + 1; //if(item >10 || item < 1) return; if(item == pre_item) return; unmark_item(pre_item); pre_item = item; mark_item(item); } void HZprocKeySelect(int x0, int y0) { char buf[80]; int len; int item = -1; //decide which key selected //because incode input from index zero begin. if(!strcasecmp(chinputime[cur_inputmethod].name,"CODE")) item = (y0 - HZServer.hzCwin.s_y1) / (HZServer.f_height + 2); else item = (y0 - HZServer.hzCwin.s_y1) / (HZServer.f_height + 2)+1; if(item == 10) item = 0; len = set_reply_default('0' + item, buf); if(len > 1) ForwardString(buf, len); } //simulate a page up void HZprocKeyUp(int x0, int y0) { char buf[80]; Display *dpy = HZServer.display; Window win2 = HZServer.window2; GC dimgc2 = HZServer.dimGC; GC lightgc2 = HZServer.lightGC; draw_tri_button(dpy, win2, dimgc2, lightgc2, HZServer.hzCwin.b1_x1, HZServer.hzCwin.b1_y1, HZServer.hzCwin.b1_x2, HZServer.hzCwin.b1_y2, HZServer.hzCwin.b1_x3, HZServer.hzCwin.b1_y3, True); wait_button_release(); draw_tri_button(dpy, win2, dimgc2, lightgc2, HZServer.hzCwin.b1_x1, HZServer.hzCwin.b1_y1, HZServer.hzCwin.b1_x2, HZServer.hzCwin.b1_y2, HZServer.hzCwin.b1_x3, HZServer.hzCwin.b1_y3, False); if(!in_box(x0, y0, HZServer.hzCwin.b1_x2, HZServer.hzCwin.b1_y1, HZServer.hzCwin.b1_x3, HZServer.hzCwin.b1_y3)) return; set_reply_default(',', buf); } //simulate a page down key void HZprocKeyDown(int x0, int y0) { char buf[80]; Display *dpy = HZServer.display; Window win2 = HZServer.window2; GC dimgc2 = HZServer.dimGC; GC lightgc2 = HZServer.lightGC; draw_tri_button(dpy, win2, dimgc2, lightgc2, HZServer.hzCwin.b2_x1, HZServer.hzCwin.b2_y1, HZServer.hzCwin.b2_x2, HZServer.hzCwin.b2_y2, HZServer.hzCwin.b2_x3, HZServer.hzCwin.b2_y3, True); wait_button_release(); draw_tri_button(dpy, win2, dimgc2, lightgc2, HZServer.hzCwin.b2_x1, HZServer.hzCwin.b2_y1, HZServer.hzCwin.b2_x2, HZServer.hzCwin.b2_y2, HZServer.hzCwin.b2_x3, HZServer.hzCwin.b2_y3, False); if(!in_box(x0, y0, HZServer.hzCwin.b2_x1, HZServer.hzCwin.b2_y1, HZServer.hzCwin.b2_x3, HZServer.hzCwin.b2_y2))return; set_reply_default('.', buf); } //draw the up and down arrows, if needed void HZoverspotDrawCandidateButton() { Display *dpy = HZServer.display; Window win2 = HZServer.window2; GC dimgc2 = HZServer.dimGC; GC lightgc2 = HZServer.lightGC; //draw up/down buttons, if any if(flag_up) draw_tri_button(dpy, win2, dimgc2, lightgc2, HZServer.hzCwin.b1_x1, HZServer.hzCwin.b1_y1, HZServer.hzCwin.b1_x2, HZServer.hzCwin.b1_y2, HZServer.hzCwin.b1_x3, HZServer.hzCwin.b1_y3, False); if(flag_down) draw_tri_button(dpy, win2, dimgc2, lightgc2, HZServer.hzCwin.b2_x1, HZServer.hzCwin.b2_y1, HZServer.hzCwin.b2_x2, HZServer.hzCwin.b2_y2, HZServer.hzCwin.b2_x3, HZServer.hzCwin.b2_y3, False); } void HZoverspotDrawCandidateArea(char *buf, int len) { int n; int flag_first; //draw text in candidate window char *ptr, *ptr1, *p,*ptr2,*ptr3; char s[256],s2[10]; int y = HZServer.f_height + 26; //draw candidate list n = 1; ptr = buf; ptr2 = buf; //printf("BUF [%s]\n", buf); printf("BUF [%x]\n", buf); if(len == 0) { XUnmapWindow(display, window2); return; } if(map_mode == 0) return; flag_first = 0; selection_count = 0; flag_found = 0; flag_up = False; flag_down = False; if(strchr(buf, '<')) flag_up = True; if(strrchr(buf, '>')) flag_down = True; while(*ptr++){ //if(count > HZServer.hzIwin.cols) break; //below code is codeset dependent !!! if(*ptr & 0x80){ flag_found = 1; if(flag_first == 0){ XMapRaised(display, window2); HZoverspotDrawCandidatePanel(); HZoverspotDrawCandidateLabel(); flag_first = 1; } ptr1 = ptr+2; while(*ptr1 & 0x80) ptr1 += 2; ptr3 = ptr+1; while(*ptr3!=' '&&*ptr3!='\t'&&*ptr3!='\n')ptr3++; strncpy(s2,ptr2,ptr-ptr2); s2[ptr-ptr2] = '\0'; ptr2 = strrchr(s2,' '); if(!ptr2) ptr2 = s2; else ptr2=ptr2+1; //if(n == 10) n = 0; sprintf(s, "%s. %s", ptr2, ptr); //printf("Inside Draw Candidate: %s. %s\n", ptr2, ptr); p = selection_list[selection_count]; strncpy(p, ptr, ptr1-ptr); p[ptr1-ptr] = '\0'; selection_count++; MyDrawString(window2, HZServer.normalGC, 6, y, s, ptr3-ptr+strlen(ptr2)+2); y += HZServer.f_height + 2; n++; ptr = ptr1; ptr2 = ptr1; if(!*ptr) break; } } if(!flag_found) XUnmapWindow(display, window2); if(flag_found)HZoverspotDrawCandidateButton(); } void HZoverspotResizeStatusWindow(IC *ic) { Window win = (Window)0; XWindowAttributes xwa; win = ic->client_win; if(!win) return; XGetWindowAttributes(display, win, &xwa); ic->sts_attr.area.x = 0; ic->sts_attr.area.y = xwa.height - FONT_HEIGHT; ic->sts_attr.area.width = xwa.width; ic->sts_attr.area.height = FONT_HEIGHT; XMoveResizeWindow(display, ic->status_win, ic->sts_attr.area.x, ic->sts_attr.area.y, ic->sts_attr.area.width, ic->sts_attr.area.height); } void HZoverspotMapStatusWindow() { IC *ic = (IC *)FindIC(last_icid); if(!ic) return; XMapRaised(display, ic->status_win); } void HZoverspotReparentStatusWindow(IC *ic) { Window win = (Window)0; XWindowAttributes xwa; win = ic->client_win; if(!win) return; XGetWindowAttributes(display, win, &xwa); ic->sts_attr.area.x = 0; ic->sts_attr.area.y = xwa.height - FONT_HEIGHT; ic->sts_attr.area.width = xwa.width; ic->sts_attr.area.height = FONT_HEIGHT; XReparentWindow(display, ic->status_win, win, ic->sts_attr.area.x, ic->sts_attr.area.y); } void HZoverspotMoveStatusWindow(IC *ic) { Window win; XWindowAttributes xwa; win = find_top_window(ic->client_win); if(!win) return; XGetWindowAttributes(display, win, &xwa); ic->sts_attr.area.x = 0; ic->sts_attr.area.y = xwa.height - 16; //ic->sts_attr.area.width = ic->sts_attr.area_needed.width; //ic->sts_attr.area.height = 16; XMoveWindow(display, ic->status_win, ic->sts_attr.area.x, ic->sts_attr.area.y); } void HZoverspotDrawInputPanel(void) { int w1 = width_input_win; int h1 = HZServer.hzCwin.h1; GC dimgc = HZServer.dimGC; GC lightgc = HZServer.lightGC; GC panelgc = HZServer.panelGC; /* fill background of two windows */ XFillRectangle(display, window1, panelgc, 0, 0, w1, h1); DrawSunkenBorder(display, window1,lightgc, dimgc, 0, 0, w1, h1); #ifdef HAVE_LIBIMLIB if(flag_noinput == 1) Imlib_paste_image(icon_id, im_chinput, window1, 4, 6, 16, 16); #endif } void HZoverspotDrawCandidatePanel(void) { Display *dpy = HZServer.display; Window win2 = HZServer.window2; int w2 = HZServer.hzCwin.w2; int h2 = HZServer.hzCwin.h2; GC dimgc2 = HZServer.dimGC; GC lightgc2 = HZServer.lightGC; GC panelgc2 = HZServer.panelGC; /* fill background of two windows */ XFillRectangle(dpy, win2, panelgc2, 0, 0, w2, h2); //draw separator XDrawLine(dpy, win2, dimgc2, 1, 23, w2-1, 23); XDrawLine(dpy, win2, lightgc2, 1, 24, w2-1, 24); //draw separator XDrawLine(dpy, win2, dimgc2, 1, h2-20, w2-1, h2-20); XDrawLine(dpy, win2, lightgc2, 1, h2-19, w2-1, h2-19); DrawSunkenBorder(dpy, win2, lightgc2, dimgc2, 0, 0, w2, h2); } void HZoverspotDrawCandidateLabel(void) { char buf[80]; strcpy(buf, ""); 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); }else if(HZServer.encoding == HZSERVER_ENCODING_BIG5){ 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); } MyDrawString(window2, HZServer.normalGC, 20, 20, buf, strlen(buf)); #ifdef HAVE_LIBIMLIB Imlib_paste_image(icon_id, im_123, window2, 4, 4, 16, 16); #endif } void HZoverspotDrawInputEntry(int x, int y, int w, int h) { Display *dpy = HZServer.display; Window win = HZServer.window1; GC dimgc = HZServer.dimGC; GC lightgc = HZServer.lightGC; XDrawLine(dpy, win, dimgc, x, y, x+w, y); XDrawLine(dpy, win, dimgc, x, y+1, x+w, y+1); XDrawLine(dpy, win, dimgc, x, y, x, y+h); XDrawLine(dpy, win, dimgc, x+1, y, x+1, y+h); XDrawLine(dpy, win, lightgc, x, y+h-2, x+w, y+h-2); XDrawLine(dpy, win, lightgc, x, y+h-1, x+w, y+h-1); XDrawLine(dpy, win, lightgc, x+w, y, x+w, y+h); XDrawLine(dpy, win, lightgc, x+w-1, y, x+w-1, y+h); } void HZoverspotStatusFlush(void) { //In overthespot style, I set the status area at the lower //part of the root window; // char buf[128]; IC *ic = (IC *)FindIC(last_icid); if(!ic) return; //only status area style supported if(!(ic->input_style & XIMStatusArea)) return; if(ic->reparented){ //if already reparented //check the new position of status window HZoverspotMoveStatusWindow(ic); //map the window and raise it to top window stack HZoverspotMapStatusWindow(); } else { //if not reparented, init all first //resize the window to fit the status area HZoverspotResizeStatusWindow(ic); //reparent it to the status area HZoverspotReparentStatusWindow(ic); //map the status window and raise it to top window stack HZoverspotMapStatusWindow(); ic->reparented = 1; } //clear status area XFillRectangle(display, ic->status_win, offspot_bggc, 0, 0, ic->sts_attr.area.width, ic->sts_attr.area.height); //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); }else if(HZServer.encoding == HZSERVER_ENCODING_BIG5){ 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); }else{ strcpy(buf, ""); if(flag_corner) strcat(buf, "[Full"); else strcat(buf, "[Half"); if(flag_punct) strcat(buf, " o]"); else strcat(buf, " .]"); strcat(buf, chinputime[cur_inputmethod].namebig5); } //printf ("before print ban jiao %s \n",buf); #ifdef HAVE_LIBIMLIB Imlib_paste_image(icon_id, im_chinput, ic->status_win, 0, 0, 16, 16); #endif MyDrawString2(ic->status_win, offspot_gc, offspot_gbgc, offspot_big5gc, 16, FONT_ASCENT, buf, strlen(buf)); } void HZoverspotCandidateFlush(void) { char mbuf[256]; if(flag_refresh)return; //Candidate area bzero(mbuf, 256); IMM_GetSelectDisplay (chinput_imm, mbuf, sizeof (mbuf)); HZoverspotDrawCandidateArea(mbuf, strlen(mbuf)); } void HZoverspotFlush(void) { //clear and draw the panel of two windows HZoverspotInputFlush(); //auxiliary window flush HZoverspotCandidateFlush(); //status window flush, this function only happens if //the client use XIMPreeditPosition|XIMStatusArea style HZoverspotStatusFlush(); }