/* event.c */ #include #include #include "iiimcfint.h" #define IIIMCF_EVENT_QUEUE_INITIAL_SLOTS_SIZE 4 #define IIIMCF_EVENT_STACK_INITIAL_SLOTS_SIZE 4 /* #define IIIMCF_EVENT_STACK */ enum IIIMCF_EVENT_STATE_FLAGS { IIIMCF_EVENT_STATE_MUSTIGNORE = (1 << 0), IIIMCF_EVENT_STATE_DISPATCHING = (1 << 1), IIIMCF_EVENT_STATE_INQUEUE = (1 << 2), IIIMCF_EVENT_STATE_BROADCASTING = (1 << 3) }; #define IIIMCF_EVENT_SET_STATE(pe, flag) ((pe)->state |= (flag)) #define IIIMCF_EVENT_RESET_STATE(pe, flag) ((pe)->state &= (~(flag))) #define IIIMCF_EVENT_IS_DISCARDABLE(pe) ((pe)->state == 0) static void delete_event( IIIMCF_event_rec *pe ) { switch (pe->type) { case IIIMCF_EVENT_TYPE_AUX_START: case IIIMCF_EVENT_TYPE_AUX_SETVALUES: case IIIMCF_EVENT_TYPE_AUX_GETVALUES: case IIIMCF_EVENT_TYPE_AUX_DRAW: case IIIMCF_EVENT_TYPE_AUX_DONE: iiimcf_delete_aux_event(pe); break; default: break; } free(pe); } /******************************************************************************** event queue and stack ********************************************************************************/ static int expand_event_queue( IIIMCF_context_rec *pc ) { int nsize; IIIMCF_event_rec **ppev; if (pc->evqueue_size == 0) { nsize = IIIMCF_EVENT_QUEUE_INITIAL_SLOTS_SIZE; ppev = (IIIMCF_event_rec**) malloc(sizeof(*ppev) * nsize); if (!ppev) return 0; memset(ppev, 0, sizeof(*ppev) * nsize); pc->ppevqueue = ppev; pc->ppev_pro = ppev; pc->ppev_con = ppev; } else { int osize = pc->evqueue_size; IIIMCF_event_rec **ppev_ncon, **ppev_npro; nsize = osize * 2; ppev = (IIIMCF_event_rec**) realloc(pc->ppevqueue, sizeof(*ppev) * nsize); if (!ppev) return 0; if (pc->ppev_con == (pc->ppev_pro + 1)) { /* p c p c v v v v +-----------------------+ +-------------------------------+ |X|X|X|X|X|X|X|X|X|X|X|X| ==> |X|X|X|X| | | | |X|X|X|X|X|X|X|X| +-----------------------+ +-------------------------------+ ^ ^ ppev ppev + nsize - (osize - (ppev_con - ppevqueue)) */ ppev_ncon = ppev + nsize - (osize - (pc->ppev_con - pc->ppevqueue)); ppev_npro = ppev + (pc->ppev_pro - pc->ppevqueue); memmove(ppev_ncon, ppev_npro + 1, sizeof(*ppev) * (nsize - (ppev_ncon - ppev))); memset(ppev_npro + 1, 0, sizeof(*ppev) * (ppev_ncon - ppev_npro - 1)); } else if ((pc->ppev_pro == pc->ppevqueue + osize) && (pc->ppev_con == pc->ppevqueue)) { /* c p c p v v v v +-----------------------+ +-------------------------------+ |X|X|X|X|X|X|X|X|X|X|X|X| ==> |X|X|X|X|X|X|X|X|X|X|X|X| | | | | +-----------------------+ +-------------------------------+ */ ppev_ncon = ppev; ppev_npro = ppev + osize; memset(ppev_npro, 0, sizeof(*ppev) * (nsize - osize)); } else { /* queue has still some empty rooms!!! */ abort(); } pc->ppevqueue = ppev; pc->ppev_pro = ppev_npro; pc->ppev_con = ppev_ncon; } pc->evqueue_size = nsize; return 1; } IIIMF_status iiimcf_store_event( IIIMCF_context_rec *pc, IIIMCF_event_rec *pe ) { int size = pc->evqueue_size; if ((!pc->ppevqueue) || ((pc->ppev_pro + 1) == pc->ppev_con)) { if (!expand_event_queue(pc)) return IIIMF_STATUS_MALLOC; } *pc->ppev_pro = pe; pc->ppev_pro++; if (pc->ppev_pro == pc->ppevqueue + size) { if (pc->ppev_con == pc->ppevqueue) { if (!expand_event_queue(pc)) return IIIMF_STATUS_MALLOC; } else { pc->ppev_pro = pc->ppevqueue; } } return IIIMF_STATUS_SUCCESS; } IIIMCF_event_rec* iiimcf_get_event( IIIMCF_context_rec *pc, int removep ) { IIIMCF_event_rec *pe; if (pc->ppev_con == pc->ppev_pro) return NULL; pe = *pc->ppev_con; if (removep) { *pc->ppev_con = NULL; if (pc->ppev_con == (pc->ppevqueue + pc->evqueue_size - 1)) pc->ppev_con = pc->ppevqueue; else pc->ppev_con++; } return pe; } #ifdef IIIMCF_EVENT_STACK static int expand_event_stack( IIIMCF_context_rec *pc ) { int nsize = pc->evstack_size; IIIMCF_event_rec **ppev; ASSERT((pc->ppevstack + nsize) == pc->ppev_sp); if (nsize == 0) nsize = IIIMCF_EVENT_STACK_INITIAL_SLOTS_SIZE; else nsize *= 2; ppev = (IIIMCF_event_rec**) realloc(pc->ppevstack, sizeof(*ppev) * nsize); if (!ppev) return 0; memset(ppev + pc->evstack_size, 0, sizeof(*ppev) * (nsize - pc->evstack_size)); pc->ppev_sp = ppev + pc->evstack_size; pc->ppevstack = ppev; pc->evstack_size = nsize; return 1; } IIIMF_status iiimcf_push_event( IIIMCF_context_rec *pc, IIIMCF_event_rec *pe ) { int nsize = pc->evstack_size; if (pc->ppev_sp == (pc->ppevstack + nsize)) { if (!expand_event_stack(pc)) return IIIMF_STATUS_MALLOC; } *pc->ppev_sp = pe; pc->ppev_sp++; return IIIMF_STATUS_SUCCESS; } IIIMCF_event_rec* iiimcf_pop_event( IIIMCF_context_rec *pc ) { IIIMCF_event_rec *pe; if (pc->ppevstack == pc->ppev_sp) return NULL; --pc->ppev_sp; pe = *pc->ppev_sp; *pc->ppev_sp = NULL; return pe; } #endif /* IIIMCF_EVENT_STACK */ /******************************************************************************** internal services ********************************************************************************/ IIIMCF_event_rec* iiimcf_make_event( IIIMCF_event_type type ) { IIIMCF_event_rec *pe; pe = (IIIMCF_event_rec*) malloc(sizeof(*pe)); if (!pe) return NULL; memset(pe, 0, sizeof(*pe)); pe->type = type; return pe; } IIIMF_status iiimcf_store_simple_event( IIIMCF_context_rec *pc, IIIMCF_event_type type ) { IIIMCF_event_rec *pe; pe = iiimcf_make_event(type); if (!pe) return IIIMF_STATUS_MALLOC; return iiimcf_store_event(pc, pe); } IIIMF_status iiimcf_delete_event_storage( IIIMCF_context_rec *pc ) { int i; IIIMCF_event_rec **ppe; if (pc->ppevqueue) { for (ppe = pc->ppevqueue, i = 0; i < pc->evqueue_size; i++, ppe++) { if (*ppe) delete_event(*ppe); } free(pc->ppevqueue); pc->ppevqueue = pc->ppev_pro = pc->ppev_con = NULL; pc->evqueue_size = 0; } #ifdef IIIMCF_EVENT_STACK if (pc->ppevstack) { for (ppe = ppevstack; ppe < pc->ppev_sp; ppe++) { if (*ppe) delete_event(*ppe); } free(pc->ppevstack); pc->ppevstack = pc->ppev_sp = NULL; pc->evstack_size = 0; } #endif return IIIMF_STATUS_SUCCESS; } static IIIMF_status broadcast( IIIMCF_context_rec *pc, IIIMCF_event_rec *pe, IIIMCF_component_rec *pcom, IIIMCF_component_rec *pcom_parent ) { IIIMF_status st1, st2; st2 = IIIMF_STATUS_SUCCESS; for (; pcom; pcom = pcom->pnext) { st1 = (*pcom->func)(pc, pe, pcom, pcom_parent); if ((st1 != IIIMF_STATUS_SUCCESS) && (st1 != IIIMF_STATUS_COMPONENT_INDIFFERENT)) st2 = st1; if (pcom->pchild) { st1 = broadcast(pc, pe, pcom->pchild, pcom); if ((st1 != IIIMF_STATUS_SUCCESS) && (st1 != IIIMF_STATUS_COMPONENT_INDIFFERENT)) st2 = st1; } } return st2; } IIIMF_status iiimcf_broadcast_event( IIIMCF_context_rec *pc, IIIMCF_event_rec *pe ) { IIIMF_status st; IIIMCF_EVENT_SET_STATE(pe, IIIMCF_EVENT_STATE_BROADCASTING); IIIMCF_SET_STATE(pc, IIIMCF_CONTEXT_BROADCASTING); st = broadcast(pc, pe, pc->ph->proot_component, NULL); IIIMCF_RESET_STATE(pc, IIIMCF_CONTEXT_BROADCASTING); IIIMCF_EVENT_RESET_STATE(pe, IIIMCF_EVENT_STATE_BROADCASTING); if (IIIMCF_EVENT_IS_DISCARDABLE(pe)) delete_event(pe); return st; } /******************************************************************************** APIs ********************************************************************************/ IIIMF_status iiimcf_get_event_type( IIIMCF_event event, IIIMCF_event_type *pevent_type ) { IIIMCF_event_rec *pe = (IIIMCF_event_rec*) event; *pevent_type = pe->type; return IIIMF_STATUS_SUCCESS; } IIIMF_status iiimcf_create_keyevent( const IIIMCF_keyevent *pkeyevent, IIIMCF_event *pevent ) { IIIMCF_event_rec *pe; pe = iiimcf_make_event(IIIMCF_EVENT_TYPE_KEYEVENT); if (!pe) return IIIMF_STATUS_MALLOC; pe->v.keyevent = *pkeyevent; *pevent = pe; return IIIMF_STATUS_SUCCESS; } IIIMF_status iiimcf_get_keyevent_value( IIIMCF_event event, IIIMCF_keyevent *pkeyevent ) { IIIMCF_event_rec *pe = (IIIMCF_event_rec*) event; if (pe->type != IIIMCF_EVENT_TYPE_KEYEVENT) return IIIMF_STATUS_ARGUMENT; *pkeyevent = pe->v.keyevent; return IIIMF_STATUS_SUCCESS; } static IIIMF_status forward_keyevent( IIIMCF_context_rec *pc, IIIMCF_event_rec *pe ) { IIIMF_status st; IIIMCF_handle_rec *ph = pc->ph; IIIMP_data_s *pds = ph->data_s; IIIMCF_keyevent *pk = &pe->v.keyevent; IIIMP_keyevent ikev; IIIMP_keyevent_list *pikl; IIIMP_contents *pcon; IIIMP_message *pmes; if (IIIMCF_IS_ENABLED(pc, IIIMCF_CONTEXT_AUTOMATIC_TRIGGER_NOTIFY)) { if (ph->server_protocol_version >= 3) st = iiimcf_process_hotkey_keyevent(pc, pk); else if (ph->server_protocol_version < 3) st = iiimcf_process_trigger_keyevent(pc, pk); if (st == IIIMF_STATUS_SUCCESS) return st; if (st != IIIMF_STATUS_NOT_TRIGGER_KEY) return st; } if (!IIIMCF_IS_STATIC_EVENT_FLOW(ph) && !IIIMCF_IS_ENABLED(pc, IIIMCF_CONTEXT_CONVERSION_MODE)) return IIIMF_STATUS_EVENT_NOT_FORWARDED; ikev.keycode = pk->keycode; ikev.keychar = pk->keychar; ikev.modifier = pk->modifier; ikev.time_stamp = pk->time_stamp; pikl = iiimp_keyevent_list_new(pds, 1, &ikev); if (!pikl) return IIIMF_STATUS_MALLOC; pcon = iiimp_contents_keyevent_list_new(pds, pikl); if (!pcon) { iiimp_keyevent_list_delete(pds, pikl); return IIIMF_STATUS_MALLOC; } pmes = iiimp_forward_event_new(pds, ph->im_id, pc->ic_id, pcon); if (!pmes) { iiimp_contents_delete(pds, pcon); return IIIMF_STATUS_MALLOC; } st = iiimcf_request_message(ph, pmes, pc, IM_FORWARD_EVENT_REPLY, NULL); return st; } static IIIMF_status forward_seticfocus( IIIMCF_context_rec *pc ) { IIIMF_status st; IIIMCF_handle_rec *ph = pc->ph; IIIMP_data_s *pds = ph->data_s; IIIMP_message *pmes; pmes = iiimp_seticfocus_new(pds, ph->im_id, pc->ic_id); if (!pmes) return IIIMF_STATUS_MALLOC; st = iiimcf_request_message(ph, pmes, pc, IM_SETICFOCUS_REPLY, NULL); return st; } IIIMF_status iiimcf_create_seticfocus_event( IIIMCF_event *pevent ) { IIIMCF_event_rec *pe; pe = iiimcf_make_event(IIIMCF_EVENT_TYPE_SETICFOCUS); if (!pe) return IIIMF_STATUS_MALLOC; *pevent = pe; return IIIMF_STATUS_SUCCESS; } static IIIMF_status forward_unseticfocus( IIIMCF_context_rec *pc ) { IIIMF_status st; IIIMCF_handle_rec *ph = pc->ph; IIIMP_data_s *pds = ph->data_s; IIIMP_message *pmes; pmes = iiimp_unseticfocus_new(pds, ph->im_id, pc->ic_id); if (!pmes) return IIIMF_STATUS_MALLOC; st = iiimcf_request_message(ph, pmes, pc, IM_UNSETICFOCUS_REPLY, NULL); return st; } IIIMF_status iiimcf_create_unseticfocus_event( IIIMCF_event *pevent ) { IIIMCF_event_rec *pe; pe = iiimcf_make_event(IIIMCF_EVENT_TYPE_UNSETICFOCUS); if (!pe) return IIIMF_STATUS_MALLOC; *pevent = pe; return IIIMF_STATUS_SUCCESS; } /* * Forwarding Event to IIIMSF. * event is deleted unless its state is marked as DISCARDABLE */ IIIMF_status iiimcf_forward_event( IIIMCF_context context, IIIMCF_event event ) { IIIMF_status st; IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context; IIIMCF_event_rec *pe = (IIIMCF_event_rec*) event; if (IIIMCF_IS_IC_INVALID(pc)) { st = iiimcf_enable_context(pc); if (st != IIIMF_STATUS_SUCCESS) { if (IIIMCF_EVENT_IS_DISCARDABLE(pe)) delete_event(pe); return IIIMF_STATUS_IC_INVALID; } } IIIMCF_RESET_STATE_CHANGE(pc, IIIMCF_STATE_PREEDIT_CHANGED | IIIMCF_STATE_LOOKUP_CHOICE_CHANGED | IIIMCF_STATE_STATUS_CHANGED | IIIMCF_STATE_COMMIT_REQUIRED); switch (pe->type) { case IIIMCF_EVENT_TYPE_KEYEVENT: st = forward_keyevent(pc, pe); break; case IIIMCF_EVENT_TYPE_TRIGGER_NOTIFY: st = iiimcf_forward_trigger_notify(pc, pe->v.number); break; case IIIMCF_EVENT_TYPE_AUX_SETVALUES: st = iiimcf_forward_aux_setvalues(pc, pe); break; case IIIMCF_EVENT_TYPE_AUX_GETVALUES: st = iiimcf_forward_aux_getvalues(pc, pe); break; case IIIMCF_EVENT_TYPE_SETICFOCUS: st = forward_seticfocus(pc); break; case IIIMCF_EVENT_TYPE_UNSETICFOCUS: st = forward_unseticfocus(pc); break; default: st = IIIMF_STATUS_EVENT_NOT_FORWARDED; } if (IIIMCF_EVENT_IS_DISCARDABLE(pe)) delete_event(pe); return st; } IIIMF_status iiimcf_receive_forwarded_event( IIIMCF_context_rec *pc, IIIMP_message *pmes ) { IIIMF_status st; IIIMP_contents *pcon = pmes->v.forward_event.contents; ASSERT(pmes->opcode == IM_FORWARD_EVENT); switch (pcon->type) { case IIIMP_CONTENTS_KEYEVENT: { int i, n; IIIMCF_event_rec *pev; IIIMCF_keyevent kev; IIIMP_keyevent_list *pkl = pcon->value.keyevent_list; IIIMP_keyevent *pimkev = pkl->keyevent; n = pkl->count; for (i = 0; i < n; i++, pimkev++) { kev.keycode = pimkev->keycode; kev.keychar = pimkev->keychar; kev.modifier = pimkev->modifier; kev.time_stamp = pimkev->time_stamp; st = iiimcf_create_keyevent(&kev, (IIIMCF_event*) &pev); if (st != IIIMF_STATUS_SUCCESS) return st; st = iiimcf_store_event(pc, pev); if (st != IIIMF_STATUS_SUCCESS) { delete_event(pev); return st; } } } case IIIMP_CONTENTS_STRING: case IIIMP_CONTENTS_TEXT: /* currently ignore */ break; default: abort(); } return IIIMF_STATUS_SUCCESS; } IIIMF_status iiimcf_dispatch_event( IIIMCF_context context, IIIMCF_event event ) { IIIMF_status st1, st2; IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context; IIIMCF_event_rec *pe = (IIIMCF_event_rec*) event; IIIMCF_component_rec *pcom, *pcom_parent; /* When broadcasting event, event dispatchment must be inhibited because if we allow it, a component may receive the same broadcasting event more than once. Eventually, we return immediately with success. */ if (IIIMCF_IS_BROADCASTING(pc)) { if (IIIMCF_EVENT_IS_DISCARDABLE(pe)) delete_event(pe); return IIIMF_STATUS_SUCCESS; } pcom_parent = pc->pcurrent_component; if (pcom_parent) pcom = pcom_parent->pchild; else pcom = pc->ph->proot_component; IIIMCF_EVENT_SET_STATE(pe, IIIMCF_EVENT_STATE_DISPATCHING); st2 = IIIMF_STATUS_COMPONENT_INDIFFERENT; for (; pcom; pcom = pcom->pnext) { pc->pcurrent_component = pcom; st1 = (*pcom->func)(pc, pe, pcom, pcom_parent); if (st1 == IIIMF_STATUS_SUCCESS) { if (st2 == IIIMF_STATUS_COMPONENT_INDIFFERENT) { st2 = IIIMF_STATUS_SUCCESS; } } else if (st1 == IIIMF_STATUS_COMPONENT_FAIL) { st2 = st1; } else if (st1 != IIIMF_STATUS_COMPONENT_INDIFFERENT) { /* fatal error. immediately quit.*/ st2 = st1; break; } } pc->pcurrent_component = pcom_parent; IIIMCF_EVENT_RESET_STATE(pe, IIIMCF_EVENT_STATE_DISPATCHING); if (IIIMCF_EVENT_IS_DISCARDABLE(pe)) delete_event(pe); return st2; } IIIMF_status iiimcf_get_next_event( IIIMCF_context context, IIIMCF_event *pevent ) { IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context; IIIMCF_event_rec *pe; pe = iiimcf_get_event(pc, 1); if (!pe) return IIIMF_STATUS_NO_EVENT; *pevent = pe; IIIMCF_EVENT_RESET_STATE(pe, IIIMCF_EVENT_STATE_INQUEUE); IIIMCF_EVENT_SET_STATE(pe, IIIMCF_EVENT_STATE_MUSTIGNORE); return IIIMF_STATUS_SUCCESS; } IIIMF_status iiimcf_peek_next_event( IIIMCF_context context, IIIMCF_event *pevent ) { IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context; IIIMCF_event_rec *pe; pe = iiimcf_get_event(pc, 0); if (!pe) return IIIMF_STATUS_NO_EVENT; *pevent = pe; IIIMCF_EVENT_SET_STATE(pe, IIIMCF_EVENT_STATE_INQUEUE); return IIIMF_STATUS_SUCCESS; } IIIMF_status iiimcf_ignore_event( IIIMCF_event event ) { IIIMCF_event_rec *pe = (IIIMCF_event_rec*) event; IIIMCF_EVENT_RESET_STATE(pe, IIIMCF_EVENT_STATE_MUSTIGNORE); if (IIIMCF_EVENT_IS_DISCARDABLE(pe)) delete_event(pe); return IIIMF_STATUS_SUCCESS; } /* Local Variables: */ /* c-file-style: "iiim-project" */ /* End: */