/* * Copyright 2003 Sun Microsystems Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Authors: Hidetoshi Tajima */ #include #include #include #include #include #include #include #include #include #include #include "iiimcf.h" #include "gtkimcontextiiim.h" #include #include "imaux.h" #include "imaux-int.h" #if defined(__sparcv9) #define SPARCV9_DIR "sparcv9/" #define SPARCV9_DIR_LEN (8) #elif defined(__amd64) #define SPARCV9_DIR "amd64/" #define SPARCV9_DIR_LEN (6) #else #undef SPARCV9_DIR NULL #define SPARCV9_DIR_LEN (0) #endif static void delete_aux_ic(GtkIMContextIIIM *context_iiim); static void iiim_aux_download (IIIMCF_downloaded_object obj); #define AUX_BASE_DIR IIIMLEDIR #define IS_SPACE(len, ptr) ((0 < (len)) && \ (('\t' == *(p)) || (' ' == *(p)))) #define IS_EOL(len, ptr) (((len) <= 0) || ('\n' == *(p))) #define IS_NOT_EOL(len, ptr) ((0 < (len)) && ('\n' != *(p))) static aux_handle_t *aux_load (char *aux_file_name); static aux_handle_t *aux_conf_load (char *aux_file_name); static aux_handle_t *aux_so_load (char * aux_file_name); static aux_t *aux_get (GtkIMContextIIIM *context_iiim, IIIMCF_event ev, const IIIMP_card16 *aux_name); static aux_entry_t *aux_entry_get (const IIIMP_card16 *name); typedef struct { int len; aux_t *aux; IIIMCF_event ev; aux_data_t *pad; } AUXComposed; /* * X auxiliary object service method */ static void service_aux_setvalue(aux_t *, const unsigned char *, int); static void service_aux_getvalue(aux_t *, const unsigned char *, int); static int service_im_id(aux_t *); static int service_ic_id(aux_t *); static void service_data_set(aux_t *, int, void *); static void * service_data_get(aux_t *, int); static Display * service_display(aux_t *); static Window service_window(aux_t *); static XPoint * service_point(aux_t *, XPoint *); static XPoint * service_point_caret(aux_t *, XPoint *); static size_t service_utf16_mb(const char **, size_t *, char **, size_t *); static size_t service_mb_utf16(const char **, size_t *, char **, size_t *); static unsigned char * service_compose(const aux_data_t *, int *); static int service_compose_size(aux_data_type_t, const unsigned char *); static aux_data_t * service_decompose(aux_data_type_t, const unsigned char *); static void service_decompose_free(aux_data_t *); static void service_register_X_filter(Display *, Window, int, int, Bool (* filter)(Display *, Window, XEvent *, XPointer), XPointer); static void service_unregister_X_filter(Display *, Window, Bool (* filter)(Display *, Window, XEvent *, XPointer), XPointer); static Bool service_server(aux_t *); static Window service_client_window(aux_t *); static Window service_focus_window(aux_t *); static int service_screen_number(aux_t *); static int service_point_screen(aux_t *, XPoint *); static int service_point_caret_screen(aux_t *, XPoint *); static Bool service_get_conversion_mode(aux_t*); static void service_set_conversion_mode(aux_t*, int); static aux_t * service_aux_get_from_id(int im_id, int ic_id, IIIMP_card16 *aux_name, int aux_name_length); static aux_service_t g_aux_service = { service_aux_setvalue, service_im_id, service_ic_id, service_data_set, service_data_get, service_display, service_window, service_point, service_point_caret, service_utf16_mb, service_mb_utf16, service_compose, service_compose_size, service_decompose, service_decompose_free, service_register_X_filter, service_unregister_X_filter, service_server, service_client_window, service_focus_window, service_screen_number, service_point_screen, service_point_caret_screen, service_get_conversion_mode, service_set_conversion_mode, service_aux_getvalue, service_aux_get_from_id }; static aux_ic_info_t * aux_ic_info = NULL; static aux_handle_t *aux_handle = NULL; /* public function */ void iiim_aux_start (GtkIMContextIIIM *context_iiim, IIIMCF_event ev) { aux_t *aux; AUXComposed ac; aux = aux_get (context_iiim, ev, NULL); if (!aux) return; memset(&ac, 0, sizeof(ac)); ac.aux = aux; ac.ev = ev; aux->im->ae->dir.method->start (aux, (XPointer) &ac, /* Always set 0! */ 0); return; } void iiim_aux_draw (GtkIMContextIIIM *context_iiim, IIIMCF_event ev) { aux_t *aux; AUXComposed ac; aux = aux_get (context_iiim, ev, NULL); if (!aux) return; memset(&ac, 0, sizeof(ac)); ac.aux = aux; ac.ev = ev; aux->im->ae->dir.method->draw(aux, (XPointer) &ac, /* Always set 0! */ 0); return; } void iiim_aux_done (GtkIMContextIIIM *context_iiim, IIIMCF_event ev) { aux_t *aux; AUXComposed ac; aux = aux_get (context_iiim, ev, NULL); if (!aux) return; memset(&ac, 0, sizeof(ac)); ac.aux = aux; ac.ev = ev; aux->im->ae->dir.method->done(aux, (XPointer) &ac, /* Always set 0! */ 0); return; } void iiim_aux_getvalues_reply (GtkIMContextIIIM *context_iiim, IIIMCF_event ev) { aux_t *aux; AUXComposed ac; aux = aux_get (context_iiim, ev, NULL); if (!aux) return; memset(&ac, 0, sizeof(ac)); ac.aux = aux; ac.ev = ev; if (aux->im->ae->dir.method->getvalues_reply) aux->im->ae->dir.method->getvalues_reply(aux, (XPointer) &ac, /* Always set 0! */ 0); return; } IIIMF_status iiim_setup_aux_object (IIIMCF_handle iiim) { IIIMF_status st; IIIMCF_object_descriptor *pdesc; IIIMCF_object_descriptor **ppdescs; IIIMCF_downloaded_object *pobjs; int i, n1, n2; n1 = 0; pdesc = NULL; st = iiimcf_get_object_descriptor_list (iiim, &n1, &pdesc); if (st != IIIMF_STATUS_SUCCESS) return st; pobjs = g_new0 (IIIMCF_downloaded_object, n1); ppdescs = g_new0 (IIIMCF_object_descriptor*, n1); for (i = 0, n2 = 0; i < n1; i++, pdesc++) { if (pdesc->predefined_id == IIIMP_IMATTRIBUTE_BINARY_GUI_OBJECT) ppdescs[n2++] = pdesc; } if (n2 > 0) { st = iiimcf_get_downloaded_objects (iiim, n2, ppdescs, pobjs); if (st != IIIMF_STATUS_SUCCESS) { g_free (ppdescs); g_free (pobjs); return st; } for (i = 0; i < n2; i++) iiim_aux_download (pobjs[i]); } g_free (ppdescs); g_free (pobjs); return IIIMF_STATUS_SUCCESS; } void IIim_aux_destrory_ic (GtkIMContextIIIM *context_iiim) { delete_aux_ic(context_iiim); } void IIim_aux_set_icfocus (GtkIMContextIIIM *context_iiim) { aux_t *aux; aux_im_data_t *aux_im; aux = aux_get (context_iiim, NULL, (IIIMP_card16 *)""); if (!aux) return; for (aux_im = aux->im_list; aux_im; aux_im = aux_im->next) { if (aux_im->ae->if_version >= AUX_IF_VERSION_2 && aux_im->ae->dir.method->set_icforcus != NULL) { aux->im = aux_im; aux_im->ae->dir.method->set_icforcus(aux); } } } void IIim_aux_unset_icfocus (GtkIMContextIIIM *context_iiim) { aux_t *aux; aux_im_data_t *aux_im; aux = aux_get (context_iiim, NULL, (IIIMP_card16 *)"\0"); if (!aux) return; for (aux_im = aux->im_list; aux_im; aux_im = aux_im->next) { if (aux_im->ae->if_version >= AUX_IF_VERSION_2 && aux_im->ae->dir.method->set_icforcus != NULL) { aux->im = aux_im; aux_im->ae->dir.method->unset_icforcus(aux); } } } void IIim_aux_shutdown () { aux_ic_info_t *aux_ic; aux_handle_t *ah; aux_handle_t *ah_next; int i; aux_t aux; while (aux_ic_info != NULL) { delete_aux_ic ((GtkIMContextIIIM *)aux_ic_info->ic_data); } (void) memset(&aux, 0, sizeof (aux)); aux.service = &g_aux_service; for (ah = aux_handle; NULL != ah; ah = ah_next) { ah_next = ah->next; for (i = 0; i < ah->ae_num; i++) { if ((ah->ae + i)->if_version >= AUX_IF_VERSION_2 && (ah->ae + i)->dir.method->destroy != NULL) { (ah->ae + i)->dir.method->destroy (&aux); } } if (NULL != ah->handle) dlclose (ah->handle); if (NULL != ah->aux_name.ptr) g_free (ah->aux_name.ptr); if (NULL != ah->file_name) g_free (ah->file_name); if (NULL != ah->ae) g_free (ah->ae); g_free (ah); } } static gchar* convert_to_string (const IIIMP_card16 *ucstr) { glong read_len, write_len; gchar *result; result = g_utf16_to_utf8 (ucstr, -1, &read_len, &write_len, NULL); return result; } static gunichar2* convert_to_utf16 (const char *str, const size_t len, glong *to_left) { glong read_len, write_len; gunichar2 *result = NULL; result = g_utf8_to_utf16 (str, len, &read_len, &write_len, NULL); *to_left = write_len; return result; } /* * object downloading */ void iiim_aux_download (IIIMCF_downloaded_object obj) { int len; char *p; char *aux_file_name; char *aux_file_name_buf; int aux_file_name_len; char *dir_name; int dir_name_len; IIIMF_status st; const IIIMP_card16 *u16filename; char file_name[MAXPATHLEN]; aux_file_name = NULL; aux_file_name_buf = NULL; st = iiimcf_get_downloaded_object_filename (obj, &u16filename); if (st != IIIMF_STATUS_SUCCESS) return; aux_file_name = convert_to_string (u16filename); if (aux_file_name == NULL) return; aux_file_name_buf = aux_file_name; if (!aux_file_name) return; aux_file_name_len = strlen (aux_file_name); /* * may not start with "/" * may not start with "../" * may not contain "/../" * may not end with "/" * may not end with "/." * may not end with "/.." * may not be ".." */ if (((1 <= aux_file_name_len) && ('/' == *(aux_file_name + 0))) || ((3 <= aux_file_name_len) && ('.' == *(aux_file_name + 0)) && ('.' == *(aux_file_name + 1)) && ('/' == *(aux_file_name + 2))) || (NULL != strstr(aux_file_name, "/../")) || ((1 <= aux_file_name_len) && ('/' == *(aux_file_name + aux_file_name_len - 1))) || ((2 <= aux_file_name_len) && ('/' == *(aux_file_name + aux_file_name_len - 2)) && ('.' == *(aux_file_name + aux_file_name_len - 1))) || ((3 <= aux_file_name_len) && ('/' == *(aux_file_name + aux_file_name_len - 3)) && ('.' == *(aux_file_name + aux_file_name_len - 2)) && ('.' == *(aux_file_name + aux_file_name_len - 1))) || ((2 == aux_file_name_len) && ('.' == *(aux_file_name + 0)) && ('.' == *(aux_file_name + 1)))) { g_free (aux_file_name_buf); return; } /* * eliminate leading "./" */ if ((2 <= aux_file_name_len) && ('.' == *(aux_file_name + 0)) && ('/' == *(aux_file_name + 1))) { aux_file_name += 2; aux_file_name_len -= 2; } dir_name = AUX_BASE_DIR; dir_name_len = strlen (dir_name); if (MAXPATHLEN < (dir_name_len + 1 + aux_file_name_len + SPARCV9_DIR_LEN + 1)) { g_free (aux_file_name_buf); return; } p = strrchr(aux_file_name, '/'); if (NULL == p) { p = aux_file_name; } else { p += 1; } memcpy(file_name, dir_name, dir_name_len); len = (p - aux_file_name); if (dir_name_len > 0 && dir_name[dir_name_len-1] == '/') { memcpy(file_name + dir_name_len, aux_file_name, len); len += dir_name_len; } else { file_name[dir_name_len] = '/'; memcpy(file_name + dir_name_len + 1, aux_file_name, len); len += (dir_name_len + 1); } #if defined(__amd64) || defined(__sparcv9) memcpy(file_name + len, SPARCV9_DIR, SPARCV9_DIR_LEN); len += SPARCV9_DIR_LEN; #endif memcpy(file_name + len, p, aux_file_name_len - (p - aux_file_name) + 1); (void)aux_load (file_name); g_free (aux_file_name_buf); return; } /* * internal method */ static aux_handle_t * aux_load (char *aux_file_name) { int fd; char buf[64]; int magic_len; int len; if (-1 == (fd = open(aux_file_name, O_RDONLY, 0))) return NULL; magic_len = strlen (AUX_CONF_MAGIC); len = read (fd, buf, magic_len); close(fd); if ((len == magic_len) && (0 == memcmp (buf, AUX_CONF_MAGIC, len))) return aux_conf_load (aux_file_name); else return aux_so_load (aux_file_name); } static aux_handle_t * aux_conf_load( char * aux_file_name ) { int fd; struct stat st_buf; void * addr; char * p; char * aux_name; int aux_name_len; char * aux_so; int aux_so_len; aux_handle_t * ah; int len; int dir_name_len; char * dir_name_last; dir_name_last = strrchr(aux_file_name, '/'); if (NULL == dir_name_last) { return NULL; } dir_name_len = ((dir_name_last - aux_file_name) + 1); if (-1 == (fd = open(aux_file_name, O_RDONLY, 0))) { return NULL; } if (0 != fstat(fd, &st_buf)) { close(fd); return NULL; } addr = mmap(0, st_buf.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); close(fd); if (MAP_FAILED == addr) { return NULL; } ah = NULL; for (p = addr, len = st_buf.st_size; 0 < len; ) { if ('#' == *p) { while (IS_NOT_EOL(len, p)) { p++; --len; } if (IS_EOL(len, p)) { p++; --len; } continue; } while (IS_SPACE(len, p)) { p++; --len; } if (IS_EOL(len, p)) { p++; --len; continue; } aux_name = p; while ((!(IS_SPACE(len, p))) && IS_NOT_EOL(len, p)) { p++; --len; } if (IS_EOL(len, p)) { p++; --len; continue; } aux_name_len = (p - aux_name); while (IS_SPACE(len, p)) { p++; --len; } if (IS_EOL(len, p)) { p++; --len; continue; } aux_so = p; while ((!(IS_SPACE(len, p))) && IS_NOT_EOL(len, p)) { p++; --len; } aux_so_len = (p - aux_so); ah = (aux_handle_t *)g_new0 (aux_handle_t, 1); if (NULL == ah) { break; } ah->aux_name.len = 0; ah->aux_name.ptr = NULL; ah->aux_name.ptr = convert_to_utf16 (aux_name, aux_name_len, (glong*)&ah->aux_name.len); if ('/' == *aux_so) { ah->file_name = g_new0 (gchar, aux_so_len + 1); } else { ah->file_name = g_new0 (gchar, dir_name_len + aux_so_len + 1); } if (NULL == ah->file_name) { g_free(ah->aux_name.ptr); g_free(ah); break; } if ('/' == *aux_so) { memcpy(ah->file_name, aux_so, aux_so_len); *(ah->file_name + aux_so_len) = '\0'; } else { memcpy(ah->file_name, aux_file_name, dir_name_len); memcpy(ah->file_name + dir_name_len, aux_so, aux_so_len); *(ah->file_name + dir_name_len + aux_so_len) = '\0'; } ah->handle = NULL; ah->ae = NULL; ah->ae_num = 0; ah->next = aux_handle; aux_handle = ah; } munmap(addr, st_buf.st_size); return ah; } /* * */ static aux_dir_t * get_aux_dir_from_aux_info (void *handle, unsigned int *ifversion) { aux_info_t *aux_info; aux_info = (aux_info_t*)dlsym(handle, AUX_INFO_SYMBOL); if (aux_info && aux_info->if_version >= AUX_IF_VERSION_2 && aux_info->register_service != NULL) { aux_info->register_service (AUX_IF_VERSION_2, &g_aux_service); *ifversion = aux_info->if_version; return aux_info->dir; } return NULL; } /* * */ static aux_handle_t * aux_so_load( char * aux_file_name ) { void * handle = (void *)NULL; aux_dir_t * aux_dir; aux_dir_t * ad; int adn; aux_handle_t * ah; aux_handle_t * ah_free; int i; unsigned int ifversion; /* * check whether the object is already loaded */ for (ah = aux_handle; NULL != ah; ah = ah->next) { if ((0 == strcmp(aux_file_name, ah->file_name)) && (NULL != ah->handle)) { return ah; } } /* * load the object and construct aux_handle_t structure for it */ handle = dlopen(aux_file_name, RTLD_LAZY); if (NULL == handle) { return NULL; } if ((aux_dir = get_aux_dir_from_aux_info (handle, &ifversion)) == NULL) { aux_dir = (aux_dir_t *)dlsym(handle, AUX_DIR_SYMBOL); if (NULL == aux_dir) { dlclose(handle); return NULL; } ifversion = 0; } for (adn = 0, ad = aux_dir; 0 < ad->name.len; ad += 1, adn += 1); if (NULL == ah) { ah = (aux_handle_t *)g_new0 (aux_handle_t, 1); if (NULL == ah) { dlclose(handle); return NULL; } memset(ah, 0, sizeof (aux_handle_t)); ah_free = ah; } else { ah_free = NULL; } if (NULL == ah->file_name) { ah->file_name = strdup(aux_file_name); if (NULL == ah->file_name) { g_free(ah); dlclose(handle); return NULL; } } ah->handle = handle; ah->ae_num = adn; ah->ae = g_new0 (aux_entry_t, adn); if (NULL == ah->ae) { if (NULL != ah_free) { g_free(ah->file_name); g_free(ah); } dlclose(handle); return NULL; } for (i = 0; i < adn; i++) { (ah->ae + i)->created = 0; memcpy(&((ah->ae + i)->dir), aux_dir + i, sizeof (aux_dir_t)); (ah->ae + i)->if_version = ifversion; } ah->next = aux_handle; aux_handle = ah; return ah; } static int auxname_strncmp (const IIIMP_card16 *s1, const IIIMP_card16 *s2, int len) { len /= sizeof (IIIMP_card16); for (;len > 0; len--, s1++, s2++) { if (*s1 > *s2) return 1; if (*s1 < *s2) return -1; if (!*s1) return 0; } if (!*s1) return 0; return 2; } static void xaux_proxy_aux_start_process(aux_t *aux, IIIMCF_event ev) { static void * handle; static void (* func)(aux_t *aux, IIIMCF_event ev); /* * TODO: need to dlclose() when im-iiim.so is unloaded. */ if ((NULL == aux) || (NULL == ev)) return; #if defined(IIIMLIBDIR) # define XIIIMP_PATH IIIMLIBDIR "/xiiimp.so.2" #else /* !IIIMLIBDIR */ # define XIIIMP_PATH "/usr/lib/iiim/xiiimp.so.2" #endif /* !IIIMLIBDIR */ if (NULL == handle) { handle = dlopen(XIIIMP_PATH, RTLD_LAZY); } #ifdef sun #define XIIIMP_PATH_X11 "/usr/X11/lib/X11/locale/common/xiiimp.so.2" #define XIIIMP_PATH_OPENWIN "/usr/openwin/lib/locale/common/xiiimp.so.2" if (NULL == handle) handle = dlopen(XIIIMP_PATH_X11, RTLD_LAZY); if (NULL == handle) handle = dlopen(XIIIMP_PATH_OPENWIN, RTLD_LAZY); #endif /* sun */ if (NULL == handle) return; func = (void (*)(aux_t *, IIIMCF_event)) dlsym(handle, "iiimxcf_xaux_proxy_aux_start"); if (NULL == func) return; func(aux, ev); } static aux_im_data_t* create_aux_im_data (aux_t *aux, IIIMCF_event ev, const IIIMP_card16 *auxname) { aux_entry_t *ae; aux_im_data_t *aux_im; GtkIMContextIIIM *context_iiim; IIIMCF_handle handle; IIIMF_status st; ae = aux_entry_get (auxname); if (!ae) return NULL; aux_im = g_new0 (aux_im_data_t, 1); /* The following members are only for fake. */ context_iiim = (GtkIMContextIIIM *)aux->ic; handle = im_info_get_handle(context_iiim->iiim_info); if (handle == NULL) return NULL; st = iiimcf_get_im_id(handle, &aux_im->im_id); if (st != IIIMF_STATUS_SUCCESS) return NULL; st = iiimcf_get_ic_id(context_iiim->context, &aux_im->ic_id); if (st != IIIMF_STATUS_SUCCESS) return NULL; /* end */ aux_im->ae = ae; aux_im->next = aux->im_list; aux->im_list = aux_im; aux->im = aux_im; if (!ae->created) { xaux_proxy_aux_start_process(aux, ev); if (!ae->dir.method->create(aux)) return NULL; ae->created = 1; } return aux_im; } static aux_t * aux_get (GtkIMContextIIIM *context_iiim, IIIMCF_event ev, const IIIMP_card16 *auxname) { IIIMF_status st; aux_t *aux; aux_im_data_t *aux_im; aux_ic_info_t *aux_ic; IIIMCF_handle handle; if (!context_iiim) return NULL; if (auxname == NULL) { st = iiimcf_get_aux_event_value (ev, &auxname, NULL, NULL, NULL, NULL, NULL); if (st != IIIMF_STATUS_SUCCESS) return NULL; } /* * create aux object if it is not created */ aux = context_iiim->aux; if (!aux) { aux = g_new0 (aux_t, 1); aux->ic = (aux_ic_data_t*)context_iiim; aux->service = &g_aux_service; context_iiim->aux = aux; aux_ic = g_new0 (aux_ic_info_t, 1); handle = im_info_get_handle(context_iiim->iiim_info); if (handle == NULL) { g_free(aux_ic); return NULL; } st = iiimcf_get_im_id(handle, &aux_ic->im_id); if (st != IIIMF_STATUS_SUCCESS) { g_free(aux_ic); return NULL; } if (context_iiim->context) { st = iiimcf_get_ic_id(context_iiim->context, &aux_ic->ic_id); if (st != IIIMF_STATUS_SUCCESS) { g_free(aux_ic); return NULL; } } aux_ic->ic_data = (aux_ic_data_t*)context_iiim; aux_ic->next = aux_ic_info; aux_ic_info = aux_ic; } if (aux) { /* * search for aux_im_data corresponding to auxname. */ if (*auxname != '\0') { for (aux_im = aux->im_list; aux_im; aux_im = aux_im->next) { if (!auxname_strncmp (auxname, aux_im->ae->dir.name.ptr, aux_im->ae->dir.name.len)) { aux->im = aux_im; return aux; } } } else { aux->im = NULL; return aux; } } aux_im = create_aux_im_data (aux, ev, auxname); if (!aux_im) return NULL; return aux; } static aux_entry_t * aux_entry_get( const IIIMP_card16 *name ) { aux_handle_t *ah; aux_handle_t *ah0; aux_entry_t *ae; int i; if (!name) return NULL; for (ah = aux_handle; NULL != ah; ah = ah->next) { if ((ah->aux_name.len > 0) && (!auxname_strncmp(name, ah->aux_name.ptr, ah->aux_name.len))) { /* This handle is created from a configuration file. Load SO now. */ ah0 = aux_so_load(ah->file_name); if (!ah0) continue; ah = ah0; } for (ae = ah->ae, i = ah->ae_num; 0 < i; ae += 1, --i) { if (!auxname_strncmp(name, ae->dir.name.ptr, ae->dir.name.len)) { return ae; } } } return NULL; } static int aux_string_length( const IIIMP_card16 *str ) { int n; for (n = 0; *str; str++, n++); return n; } static AUXComposed* create_composed_from_event( aux_t *aux, IIIMCF_event ev ) { unsigned char *p; AUXComposed *pac; IIIMF_status st; const IIIMP_card16 *aux_name; IIIMP_card32 class_idx; int num_intvals; const IIIMP_card32 *pintvals; int num_strvals; const IIIMP_card16 **pstrs; aux_data_t *pad; int i, n; int aux_data_t_n; int aux_name_len, aux_name_n; int integer_list_n, string_list_n; int string_n; int *pstring_len; #define ROUNDUP(n) ((n + sizeof(void *) - 1) / sizeof(void *) * sizeof(void *)) st = iiimcf_get_aux_event_value(ev, &aux_name, &class_idx, &num_intvals, &pintvals, &num_strvals, &pstrs); if (st != IIIMF_STATUS_SUCCESS) return NULL; /* first of all, caliculate size. */ n = ROUNDUP(sizeof(AUXComposed)); aux_data_t_n = n; n += sizeof(aux_data_t); aux_name_n = n = ROUNDUP(n); aux_name_len = aux_string_length(aux_name); n += (aux_name_len + 1) * sizeof(IIIMP_card16); if (num_intvals > 0) { integer_list_n = n = ROUNDUP(n); n += num_intvals * sizeof(int); } pstring_len = NULL; if (num_strvals > 0) { pstring_len = (int*) malloc(sizeof(int) * num_strvals); if (!pstring_len) return NULL; string_list_n = n = ROUNDUP(n); n += num_strvals * sizeof(aux_string_t); string_n = n = ROUNDUP(n); for (i = 0; i < num_strvals; i++) { pstring_len[i] = aux_string_length(pstrs[i]); n += (pstring_len[i] + 1) * sizeof(IIIMP_card16); } } p = (unsigned char*) malloc(n); if (!p) { if (pstring_len) free(pstring_len); return NULL; } memset(p, 0, n); pac = (AUXComposed*) p; pac->len = n; pac->ev = ev; pad = (aux_data_t*)(p + aux_data_t_n); pac->pad = pad; if (aux) { pac->aux = aux; pad->im = aux->im->im_id; pad->ic = aux->im->ic_id; } pad->aux_index = class_idx; pad->aux_name = p + aux_name_n; memcpy(pad->aux_name, aux_name, (aux_name_len + 1) * sizeof(IIIMP_card16)); pad->aux_name_length = aux_name_len * sizeof(IIIMP_card16); pad->integer_count = num_intvals; if (num_intvals > 0) { pad->integer_list = (int*)(p + integer_list_n); for (i = 0; i < num_intvals; i++) { pad->integer_list[i] = pintvals[i]; } } pad->string_count = num_strvals; pad->string_ptr = p; if (num_strvals > 0) { aux_string_t *pas; pad->string_list = pas = (aux_string_t*)(p + string_list_n); p += string_n; for (i = 0; i < num_strvals; i++, pas++) { pas->length = pstring_len[i] * sizeof(IIIMP_card16); pas->ptr = p; n = (pstring_len[i] + 1) * sizeof(IIIMP_card16); memcpy(p, pstrs[i], n); p += n; } } if (pstring_len) free(pstring_len); return pac; #undef ROUNDUP } static AUXComposed* create_composed_from_aux_data(const aux_data_t *pad1, int *size) { unsigned char *p; AUXComposed *pac; aux_data_t *pad2; int i, n; int aux_data_t_n; int aux_name_n; int integer_list_n, string_list_n; int string_n; #define ROUNDUP(n) ((n + sizeof(void *) - 1) / sizeof(void *) * sizeof(void *)) /* first of all, caliculate size. */ n = ROUNDUP(sizeof(AUXComposed)); aux_data_t_n = n; n += sizeof(aux_data_t); aux_name_n = n = ROUNDUP(n); n += pad1->aux_name_length + sizeof(IIIMP_card16); integer_list_n = n = ROUNDUP(n); n += pad1->integer_count * sizeof(int); string_list_n = n = ROUNDUP(n); n += pad1->string_count * sizeof(aux_string_t); string_n = n = ROUNDUP(n); for (i = 0; i < pad1->string_count; i++) { n += pad1->string_list[i].length + sizeof(IIIMP_card16); } p = (unsigned char*) malloc(n); if (!p) return NULL; memset(p, 0, n); if (size) *size = n; pac = (AUXComposed*) p; pac->len = n; pad2 = (aux_data_t*)(p + aux_data_t_n); pac->pad = pad2; *pad2 = *pad1; pad2->aux_name = p + aux_name_n; memcpy(pad2->aux_name, pad1->aux_name, pad1->aux_name_length); if (pad1->integer_count > 0) { pad2->integer_list = (int*)(p + integer_list_n); memcpy(pad2->integer_list, pad1->integer_list, sizeof(int) * pad1->integer_count); } else { pad2->integer_list = NULL; } pad2->string_ptr = p; if (pad1->string_count > 0) { aux_string_t *pas1, *pas2; pas1= pad1->string_list; pad2->string_list = pas2 = (aux_string_t*)(p + string_list_n); p += string_n; for (i = 0; i < pad1->string_count; i++, pas1++, pas2++) { pas2->length = pas1->length; pas2->ptr = p; memcpy(p, pas1->ptr, pas2->length); p += pas2->length + sizeof(IIIMP_card16); } } else { pad2->string_list = NULL; } return pac; #undef ROUNDUP } static void delete_aux_ic(GtkIMContextIIIM *context_iiim) { aux_t *aux; aux_im_data_t *aux_im; aux_ic_info_t *aux_ic; aux_ic_info_t *prev_aux_ic; aux = aux_get (context_iiim, NULL, (IIIMP_card16 *)""); if (aux) { for (aux_im = aux->im_list; aux_im; aux_im = aux_im->next) { if (aux_im->ae->if_version >= AUX_IF_VERSION_2 && aux_im->ae->dir.method->destroy_ic != NULL) { aux->im = aux_im; aux_im->ae->dir.method->destroy_ic(aux); } } } prev_aux_ic = NULL; for (aux_ic = aux_ic_info; aux_ic != NULL; aux_ic = aux_ic->next) { if (aux_ic->ic_data == (aux_ic_data_t *)context_iiim) { if (prev_aux_ic == NULL) aux_ic_info = aux_ic->next; else prev_aux_ic->next = aux_ic->next; g_free(aux_ic); break; } prev_aux_ic = aux_ic; } } /* * aux service function */ static void service_aux_setvalue( aux_t * aux, const unsigned char * p, int len ) { AUXComposed *pac = (AUXComposed*) p; if (pac->ev) { im_context_aux_set_values ((GtkIMContextIIIM*)aux->ic, pac->ev); } else if (pac->pad) { int i; aux_data_t *pad = pac->pad; IIIMF_status st; IIIMCF_event ev; IIIMP_card32 *pintvals; const IIIMP_card16 **pstrs; if (pad->integer_count > 0) { pintvals = (IIIMP_card32*) malloc(sizeof(*pintvals) * pad->integer_count); if (!pintvals) return; for (i = 0; i < pad->integer_count; i++) { pintvals[i] = pad->integer_list[i]; } } else { pintvals = NULL; } if (pad->string_count > 0) { pstrs = (const IIIMP_card16**) malloc(sizeof(*pstrs) * pad->string_count); if (!pstrs) { if (pintvals) free(pintvals); return; } for (i = 0; i < pad->string_count; i++) { pstrs[i] = (const IIIMP_card16*) pad->string_list[i].ptr; } } else { pstrs = NULL; } st = iiimcf_create_aux_setvalues_event((IIIMP_card16*) pad->aux_name, pad->aux_index, pad->integer_count, pintvals, pad->string_count, pstrs, &ev); if (st == IIIMF_STATUS_SUCCESS) im_context_aux_set_values ((GtkIMContextIIIM*)aux->ic, ev); if (pintvals) free(pintvals); if (pstrs) free(pstrs); } } static void service_aux_getvalue( aux_t * aux, const unsigned char * p, int len ) { AUXComposed *pac = (AUXComposed*) p; if (pac->ev) im_context_aux_get_values ((GtkIMContextIIIM*)aux->ic, pac->ev); else if (pac->pad) { int i; aux_data_t *pad = pac->pad; IIIMF_status st; IIIMCF_event ev; IIIMP_card32 *pintvals; const IIIMP_card16 **pstrs; if (pad->integer_count > 0) { pintvals = (IIIMP_card32*) malloc(sizeof(*pintvals) * pad->integer_count); if (!pintvals) return; for (i = 0; i < pad->integer_count; i++) { pintvals[i] = pad->integer_list[i]; } } else { pintvals = NULL; } if (pad->string_count > 0) { pstrs = (const IIIMP_card16**) malloc(sizeof(*pstrs) * pad->string_count); if (!pstrs) { if (pintvals) free(pintvals); return; } for (i = 0; i < pad->string_count; i++) { pstrs[i] = (const IIIMP_card16*) pad->string_list[i].ptr; } } else { pstrs = NULL; } st = iiimcf_create_aux_getvalues_event((IIIMP_card16*) pad->aux_name, pad->aux_index, pad->integer_count, pintvals, pad->string_count, pstrs, &ev); if (st == IIIMF_STATUS_SUCCESS) im_context_aux_get_values((GtkIMContextIIIM*)aux->ic, ev); if (pintvals) free(pintvals); if (pstrs) free(pstrs); } } static int service_im_id( aux_t * aux ) { return aux->im->im_id; } static int service_ic_id( aux_t * aux ) { return aux->im->ic_id; } static void service_data_set( aux_t * aux, int im_id, void * data ) { aux_im_data_t * aux_im; for (aux_im = aux->im; NULL != aux_im; aux_im = aux_im->next) { if (im_id == aux_im->im_id) { aux_im->data = data; } } return; } static void * service_data_get( aux_t * aux, int im_id ) { aux_im_data_t * aux_im; for (aux_im = aux->im; NULL != aux_im; aux_im = aux_im->next) { if (im_id == aux_im->im_id) { return aux_im->data; } } return NULL; } static Display * service_display( aux_t * aux ) { GtkIMContextIIIM *context = (GtkIMContextIIIM*)aux->ic; GdkScreen *screen = im_info_get_screen (context->iiim_info); if (screen != NULL) return GDK_SCREEN_XDISPLAY (screen); else return NULL; } static Window service_window( aux_t * aux ) { GtkIMContextIIIM *context = (GtkIMContextIIIM*)aux->ic; if (context->client_window) return GDK_WINDOW_XWINDOW (context->client_window); else return None; } static XPoint * service_point( aux_t * aux, XPoint * point ) { GtkIMContextIIIM *context = (GtkIMContextIIIM*)aux->ic; point->x = context->cursor.x; point->y = context->cursor.y + context->cursor.height; return point; } static XPoint * service_point_caret( aux_t * aux, XPoint * point ) { return service_point(aux, point); } /* convert a utf16 string into a string in locale's encoding Return value : The byte length of the converted string */ static size_t service_utf16_mb ( const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft ) { gchar *utf8_string = NULL; gsize bytes_read = 0, bytes_written = 0; gchar *result = NULL; utf8_string = convert_to_string ((const IIIMP_card16 *)(*inbuf)); result = g_locale_from_utf8 (utf8_string, -1, &bytes_read, &bytes_written, NULL); strcpy (*outbuf, result); outbuf += bytes_written; *inbytesleft -= bytes_read; *outbytesleft -= bytes_written; g_free (utf8_string); g_free (result); return (size_t)bytes_written; } /* convert a string in locale's encoding into a utf16 string. Return value : The byte length of the converted string */ static size_t service_mb_utf16( const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft ) { gchar *utf8_string = NULL; gsize bytes_read = 0, bytes_written = 0; gsize r; gunichar2 *result = NULL; utf8_string = g_locale_to_utf8 ((const char*)(*inbuf), *inbytesleft, &bytes_read, &bytes_written, NULL); result = convert_to_utf16 (utf8_string, -1, (glong*)&r); memcpy (*outbuf, result, r); outbuf += r; *inbytesleft -= bytes_read; *outbytesleft -= r; g_free (utf8_string); g_free (result); return (size_t)r; } static unsigned char * service_compose( const aux_data_t *pad, int *size ) { AUXComposed *pac; pac = create_composed_from_aux_data(pad, size); return (unsigned char*) pac; } static int service_compose_size( aux_data_type_t type, const unsigned char *p ) { /* now this function is dummy... */ return 0; } static aux_data_t * service_decompose( aux_data_type_t type, const unsigned char * p ) { AUXComposed *pac = (AUXComposed*) p; if (pac->pad) { pac = create_composed_from_aux_data(pac->pad, NULL); if (!pac) return NULL; pac->pad->type = type; return pac->pad; } if (pac->ev) { pac = create_composed_from_event(pac->aux, pac->ev); if (!pac) return NULL; pac->pad->type = type; return pac->pad; } return NULL; } static void service_decompose_free( aux_data_t *pad ) { if (!pad) return; if (!pad->string_ptr) return; free(pad->string_ptr); } static void service_register_X_filter( Display * display, Window window, int start_type, int end_type, Bool (* filter)(Display *, Window, XEvent *, XPointer), XPointer client_data ) { _XRegisterFilterByType(display, window, start_type, end_type, filter, client_data); return; } static void service_unregister_X_filter( Display *display, Window window, Bool (* filter)(Display *, Window, XEvent *, XPointer), XPointer client_data ) { _XUnregisterFilter(display, window, filter, client_data); } static Bool service_server( aux_t * aux ) { return False; } static Window service_client_window( aux_t * aux ) { GtkIMContextIIIM *context = (GtkIMContextIIIM*)aux->ic; if (context->client_window) return GDK_WINDOW_XWINDOW (context->client_window); else return None; } static Window service_focus_window( aux_t * aux ) { GtkIMContextIIIM *context = (GtkIMContextIIIM*)aux->ic; if (context->client_window) return GDK_WINDOW_XWINDOW (context->client_window); else return None; } static int service_screen_number( aux_t * aux ) { GtkIMContextIIIM *context = (GtkIMContextIIIM*)aux->ic; GdkScreen *screen = im_info_get_screen (context->iiim_info); if (screen != NULL) return gdk_screen_get_number (screen); else return -1; } static int service_point_screen( aux_t * aux, XPoint * point ) { Display *display; Window window = None; Window root_window = None; Window child = None; int screen_number; int new_x; int new_y; display = service_display (aux); if (display == NULL) { point->x = -1; point->y = -1; return -1; } screen_number = service_screen_number (aux); root_window = RootWindow (display, screen_number); service_point (aux, point); window = service_window (aux); XTranslateCoordinates (display, window, root_window, point->x, point->y, &new_x, &new_y, &child); point->x = new_x; point->y = new_y; return screen_number; } static int service_point_caret_screen( aux_t * aux, XPoint * point ) { return service_point_screen (aux, point); } static Bool service_get_conversion_mode(aux_t * aux) { GtkIMContextIIIM *context = (GtkIMContextIIIM*)aux->ic; gboolean conversion_mode = FALSE; if (context) iiimcf_get_current_conversion_mode (context->context, &conversion_mode); return conversion_mode; } static void service_set_conversion_mode(aux_t * aux, int conversion_mode) { GtkIMContextIIIM *context = (GtkIMContextIIIM*)aux->ic; if (context) { if (conversion_mode == 1) im_context_change_conversion_mode (context, "on"); else im_context_change_conversion_mode (context, "off"); } } static aux_t * service_aux_get_from_id(int im_id, int ic_id, IIIMP_card16 *aux_name, int aux_name_length) { aux_ic_info_t *aux_ic; for (aux_ic = aux_ic_info; aux_ic != NULL; aux_ic = aux_ic->next) { if (aux_ic->im_id == im_id && aux_ic->ic_id == ic_id) break; } if (aux_ic == NULL) return NULL; return aux_get((GtkIMContextIIIM *)aux_ic->ic_data, NULL, aux_name); } /* Local Variables: */ /* c-file-style: "iiim-project" */ /* End: */