4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * Ion is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
13 #include <libtu/objp.h>
22 #include <libextl/extl.h>
27 static void waitrelease(WRegion *reg);
28 static void submapgrab(WRegion *reg);
31 static void insstr(WWindow *wwin, XKeyEvent *ev)
33 static XComposeStatus cs={NULL, 0};
40 if(XFilterEvent((XEvent*)ev, ev->window))
42 n=XmbLookupString(wwin->xic, ev, buf, 16, &ksym, &stat);
43 if(stat!=XLookupChars && stat!=XLookupBoth)
46 n=XLookupString(ev, buf, 32, &ksym, &cs);
52 /* Won't catch bad strings, but should filter out most crap. */
54 if(!iswprint(str_wchar_at(buf, 32)))
61 window_insstr(wwin, buf, n);
65 static void send_key(XEvent *ev, WClientWin *cwin)
69 ev->xkey.subwindow=None;
70 XSendEvent(ioncore_g.dpy, win, False, KeyPressMask, ev);
74 static bool quote_next_handler(WRegion *reg, XEvent *xev)
76 XKeyEvent *ev=&xev->xkey;
77 if(ev->type!=KeyPress)
79 if(ioncore_ismod(ev->keycode))
81 assert(OBJ_IS(reg, WClientWin));
82 send_key(xev, (WClientWin*)reg);
83 return TRUE; /* remove the grab */
88 * Send next key press directly to \var{cwin}.
91 void clientwin_quote_next(WClientWin *cwin)
93 ioncore_grab_establish((WRegion*)cwin, quote_next_handler, NULL, 0);
94 ioncore_change_grab_cursor(IONCORE_CURSOR_WAITKEY);
98 static bool waitrelease_handler(WRegion *reg, XEvent *ev)
100 if(!ioncore_unmod(ev->xkey.state, ev->xkey.keycode))
106 static void waitrelease(WRegion *reg)
108 if(ioncore_modstate()==0)
111 /* We need to grab on the root window as <reg> might have been
112 * ioncore_defer_destroy:ed by the binding handler (the most common case
113 * for using this kpress_wait!). In such a case the grab may
114 * be removed before the modifiers are released.
116 ioncore_grab_establish((WRegion*)region_rootwin_of(reg),
119 ioncore_change_grab_cursor(IONCORE_CURSOR_WAITKEY);
123 static void free_subs(WSubmapState *p)
135 static void clear_subs(WRegion *reg)
137 while(reg->submapstat!=NULL){
138 WSubmapState *tmp=reg->submapstat;
139 reg->submapstat=tmp->next;
145 static bool add_sub(WRegion *reg, uint key, uint state)
150 if(reg->submapstat==NULL){
151 p=&(reg->submapstat);
159 s=ALLOC(WSubmapState);
174 static XKeyEvent *current_key_event=NULL;
175 static uint current_kcb, current_state;
176 static bool current_submap;
178 /* Note: state set to AnyModifier for submaps */
179 bool ioncore_current_key(uint *kcb, uint *state, bool *sub)
185 *state=current_state;
192 /* Return value TRUE = grab needed */
193 static bool do_key(WRegion *reg, XKeyEvent *ev)
195 WBinding *binding=NULL;
196 WRegion *oreg=NULL, *binding_owner=NULL, *subreg=NULL;
200 grabbed=(oreg->flags®ION_BINDINGS_ARE_GRABBED);
203 /* Find the deepest nested active window grabbing this key. */
204 while(reg->active_sub!=NULL)
208 binding=region_lookup_keybinding(reg, ev, oreg->submapstat,
213 if(OBJ_IS(reg, WRootWin))
217 reg=REGION_PARENT_REG(reg);
220 binding=region_lookup_keybinding(oreg, ev, oreg->submapstat,
225 if(binding->submap!=NULL){
226 if(add_sub(oreg, ev->keycode, ev->state))
230 }else if(binding_owner!=NULL){
231 WRegion *mgd=region_managed_within(binding_owner, subreg);
232 bool subs=(oreg->submapstat!=NULL);
237 XUngrabKeyboard(ioncore_g.dpy, CurrentTime);
239 current_kcb=ev->keycode;
240 current_state=ev->state;
243 /* TODO: having to pass both mgd and subreg for some handlers
244 * to work is ugly and complex.
246 extl_call(binding->func, "ooo", NULL, binding_owner, mgd, subreg);
250 if(ev->state!=0 && !subs && binding->wait)
253 }else if(oreg->submapstat!=NULL){
255 }else if(OBJ_IS(oreg, WWindow)){
256 insstr((WWindow*)oreg, ev);
263 static bool submapgrab_handler(WRegion* reg, XEvent *xev)
265 XKeyEvent *ev=&xev->xkey;
266 if(ev->type!=KeyPress)
268 if(ioncore_ismod(ev->keycode))
270 return !do_key(reg, ev);
274 static void submapgrab(WRegion *reg)
276 ioncore_grab_establish(reg, submapgrab_handler, clear_subs, 0);
277 ioncore_change_grab_cursor(IONCORE_CURSOR_WAITKEY);
281 void ioncore_do_handle_keypress(XKeyEvent *ev)
283 WRegion *reg=(WRegion*)XWINDOW_REGION_OF(ev->window);