2 * ion/ioncore/pointer.c
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.
26 static uint p_button=0, p_state=0;
27 static int p_x=-1, p_y=-1;
28 static int p_orig_x=-1, p_orig_y=-1;
29 static bool p_motion=FALSE;
30 static int p_clickcnt=0;
33 static enum{ST_NO, ST_INIT, ST_HELD} p_grabstate=ST_NO;
35 static WButtonHandler *p_motion_end_handler=NULL;
36 static WMotionHandler *p_motion_handler=NULL;
37 static WMotionHandler *p_motion_begin_handler=NULL;
38 static GrabHandler *p_key_handler=NULL;
39 static GrabKilledHandler *p_killed_handler=NULL;
41 static Watch p_regwatch=WATCH_INIT, p_subregwatch=WATCH_INIT;
43 #define p_reg ((WRegion*)p_regwatch.obj)
44 #define p_subreg ((WRegion*)p_subregwatch.obj)
50 /*{{{ Handler setup */
53 bool ioncore_set_drag_handlers(WRegion *reg,
54 WMotionHandler *begin,
55 WMotionHandler *motion,
57 GrabHandler *keypress,
58 GrabKilledHandler *killed)
60 if(ioncore_pointer_grab_region()==NULL || p_motion)
63 /* A motion handler set at this point may not set a begin handler */
64 if(p_grabstate!=ST_HELD && begin!=NULL)
68 watch_setup(&p_regwatch, (Obj*)reg, NULL);
69 watch_reset(&p_subregwatch);
72 p_motion_begin_handler=begin;
73 p_motion_handler=motion;
74 p_motion_end_handler=end;
75 p_key_handler=keypress;
76 p_killed_handler=killed;
89 static bool time_in_threshold(Time time)
98 return t<ioncore_g.dblclick_delay;
102 static bool motion_in_threshold(int x, int y)
104 return (x>p_x-CF_DRAG_TRESHOLD && x<p_x+CF_DRAG_TRESHOLD &&
105 y>p_y-CF_DRAG_TRESHOLD && y<p_y+CF_DRAG_TRESHOLD);
109 WRegion *ioncore_pointer_grab_region()
111 if(p_grabstate==ST_NO)
120 /*{{{ Call handlers */
123 static XEvent *p_curr_event=NULL;
126 XEvent *ioncore_current_pointer_event()
132 static void call_button(WBinding *binding, XButtonEvent *ev)
139 p_curr_event=(XEvent*)ev;
140 extl_call(binding->func, "oo", NULL, p_reg, p_subreg);
145 static void call_motion(XMotionEvent *ev, int dx, int dy)
147 if(p_motion_handler!=NULL && p_reg!=NULL){
148 p_curr_event=(XEvent*)ev;
149 p_motion_handler(p_reg, ev, dx, dy);
155 static void call_motion_end(XButtonEvent *ev)
157 if(p_motion_end_handler!=NULL && p_reg!=NULL){
158 p_curr_event=(XEvent*)ev;
159 p_motion_end_handler(p_reg, ev);
165 static void call_motion_begin(WBinding *binding, XMotionEvent *ev,
173 p_curr_event=(XEvent*)ev;
175 extl_call(binding->func, "oo", NULL, p_reg, p_subreg);
177 if(p_motion_begin_handler!=NULL && p_reg!=NULL)
178 p_motion_begin_handler(p_reg, ev, dx, dy);
180 p_motion_begin_handler=NULL;
189 /*{{{ ioncore_handle_button_press/release/motion */
192 static void finish_pointer()
195 window_release((WWindow*)p_reg);
197 watch_reset(&p_subregwatch);
201 static bool handle_key(WRegion *reg, XEvent *ev)
203 if(p_key_handler!=NULL){
204 if(p_key_handler(reg, ev)){
213 static void pointer_grab_killed(WRegion *unused)
215 if(p_reg!=NULL && p_killed_handler!=NULL)
216 p_killed_handler(p_reg);
217 watch_reset(&p_regwatch);
222 bool ioncore_do_handle_buttonpress(XButtonEvent *ev)
224 WBinding *pressbind=NULL;
226 WRegion *subreg=NULL;
233 reg=(WRegion*)XWINDOW_REGION_OF_T(ev->window, WWindow);
238 if(ev->subwindow!=None){
239 XButtonEvent ev2=*ev;
240 ev2.window=ev->subwindow;
241 if(XTranslateCoordinates(ioncore_g.dpy, ev->window, ev2.window,
242 ev->x, ev->y, &(ev2.x), &(ev2.y),
244 if(ioncore_do_handle_buttonpress(&ev2))
249 dblclick=(p_clickcnt==1 && time_in_threshold(ev->time) &&
250 p_button==button && p_state==state && reg==p_reg);
253 p_motion_begin_handler=NULL;
254 p_motion_handler=NULL;
255 p_motion_end_handler=NULL;
257 p_killed_handler=NULL;
261 p_orig_x=p_x=ev->x_root;
262 p_orig_y=p_y=ev->y_root;
266 watch_setup(&p_regwatch, (Obj*)reg, NULL);
268 subreg=region_current(reg);
269 p_area=window_press((WWindow*)reg, ev, &subreg);
271 watch_setup(&p_subregwatch, (Obj*)subreg, NULL);
274 pressbind=region_lookup_binding(reg, BINDING_BUTTONDBLCLICK, state,
279 pressbind=region_lookup_binding(reg, BINDING_BUTTONPRESS, state,
283 ioncore_grab_establish(reg, handle_key, pointer_grab_killed, 0);
286 call_button(pressbind, ev);
292 bool ioncore_do_handle_buttonrelease(XButtonEvent *ev)
294 WBinding *binding=NULL;
296 if(p_button!=ev->button)
302 binding=region_lookup_binding(p_reg, BINDING_BUTTONCLICK,
303 p_state, p_button, p_area);
304 call_button(binding, ev);
311 ioncore_grab_remove(handle_key);
318 void ioncore_do_handle_motionnotify(XMotionEvent *ev)
321 WBinding *binding=NULL;
327 if(motion_in_threshold(ev->x_root, ev->y_root))
329 binding=region_lookup_binding(p_reg, BINDING_BUTTONMOTION,
330 p_state, p_button, p_area);
340 call_motion_begin(binding, ev, dx, dy);
343 call_motion(ev, dx, dy);