2 * ion/ioncore/pointer.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
23 static uint p_button
=0, p_state
=0;
24 static int p_x
=-1, p_y
=-1;
25 static int p_orig_x
=-1, p_orig_y
=-1;
26 static bool p_motion
=FALSE
;
27 static int p_clickcnt
=0;
30 static enum{ST_NO
, ST_INIT
, ST_HELD
} p_grabstate
=ST_NO
;
32 static WButtonHandler
*p_motion_end_handler
=NULL
;
33 static WMotionHandler
*p_motion_handler
=NULL
;
34 static WMotionHandler
*p_motion_begin_handler
=NULL
;
35 static GrabHandler
*p_key_handler
=NULL
;
36 static GrabKilledHandler
*p_killed_handler
=NULL
;
38 static Watch p_regwatch
=WATCH_INIT
, p_subregwatch
=WATCH_INIT
;
40 #define p_reg ((WRegion*)p_regwatch.obj)
41 #define p_subreg ((WRegion*)p_subregwatch.obj)
47 /*{{{ Handler setup */
50 bool ioncore_set_drag_handlers(WRegion
*reg
,
51 WMotionHandler
*begin
,
52 WMotionHandler
*motion
,
54 GrabHandler
*keypress
,
55 GrabKilledHandler
*killed
)
57 if(ioncore_pointer_grab_region()==NULL
|| p_motion
)
60 /* A motion handler set at this point may not set a begin handler */
61 if(p_grabstate
!=ST_HELD
&& begin
!=NULL
)
65 watch_setup(&p_regwatch
, (Obj
*)reg
, NULL
);
66 watch_reset(&p_subregwatch
);
69 p_motion_begin_handler
=begin
;
70 p_motion_handler
=motion
;
71 p_motion_end_handler
=end
;
72 p_key_handler
=keypress
;
73 p_killed_handler
=killed
;
86 static bool time_in_threshold(Time time
)
95 return t
<ioncore_g
.dblclick_delay
;
99 static bool motion_in_threshold(int x
, int y
)
101 return (x
>p_x
-CF_DRAG_TRESHOLD
&& x
<p_x
+CF_DRAG_TRESHOLD
&&
102 y
>p_y
-CF_DRAG_TRESHOLD
&& y
<p_y
+CF_DRAG_TRESHOLD
);
106 WRegion
*ioncore_pointer_grab_region()
108 if(p_grabstate
==ST_NO
)
117 /*{{{ Call handlers */
120 static XEvent
*p_curr_event
=NULL
;
123 XEvent
*ioncore_current_pointer_event()
129 static void call_button(WBinding
*binding
, XButtonEvent
*ev
)
134 p_curr_event
=(XEvent
*)ev
;
135 extl_call(binding
->func
, "ooo", NULL
, p_reg
, p_subreg
,
136 (p_reg
!=NULL
? p_reg
->active_sub
: NULL
));
141 static void call_motion(XMotionEvent
*ev
, int dx
, int dy
)
143 if(p_motion_handler
!=NULL
&& p_reg
!=NULL
){
144 p_curr_event
=(XEvent
*)ev
;
145 p_motion_handler(p_reg
, ev
, dx
, dy
);
151 static void call_motion_end(XButtonEvent
*ev
)
153 if(p_motion_end_handler
!=NULL
&& p_reg
!=NULL
){
154 p_curr_event
=(XEvent
*)ev
;
155 p_motion_end_handler(p_reg
, ev
);
161 static void call_motion_begin(WBinding
*binding
, XMotionEvent
*ev
,
167 p_curr_event
=(XEvent
*)ev
;
169 extl_call(binding
->func
, "oo", NULL
, p_reg
, p_subreg
);
171 if(p_motion_begin_handler
!=NULL
&& p_reg
!=NULL
)
172 p_motion_begin_handler(p_reg
, ev
, dx
, dy
);
174 p_motion_begin_handler
=NULL
;
183 /*{{{ ioncore_handle_button_press/release/motion */
186 static void finish_pointer()
189 window_release((WWindow
*)p_reg
);
191 watch_reset(&p_subregwatch
);
195 static bool handle_key(WRegion
*reg
, XEvent
*ev
)
197 if(p_key_handler
!=NULL
){
198 if(p_key_handler(reg
, ev
)){
207 static void pointer_grab_killed(WRegion
*UNUSED(unused
))
209 if(p_reg
!=NULL
&& p_killed_handler
!=NULL
)
210 p_killed_handler(p_reg
);
211 watch_reset(&p_regwatch
);
216 static bool listens_to(WRegion
*reg
, uint state
, uint button
, int area
)
218 static const int acts
[]={BINDING_BUTTONMOTION
, BINDING_BUTTONCLICK
,
219 BINDING_BUTTONDBLCLICK
};
220 static const int n_acts
=3;
223 for(i
=0; i
<n_acts
; i
++){
224 if(region_lookup_binding(reg
, acts
[i
], state
, button
, area
))
232 static bool ioncore_dodo_handle_buttonpress(XButtonEvent
*ev
, bool sub
)
234 WBinding
*pressbind
=NULL
;
236 WRegion
*subreg
=NULL
;
244 reg
=(WRegion
*)XWINDOW_REGION_OF_T(ev
->window
, WWindow
);
249 dblclick
=(p_clickcnt
==1 && time_in_threshold(ev
->time
) &&
250 p_button
==button
&& p_state
==state
);
252 if(dblclick
&& p_reg
!=reg
){
258 subreg
=region_current(reg
);
259 area
=window_press((WWindow
*)reg
, ev
, &subreg
);
262 pressbind
=region_lookup_binding(reg
, BINDING_BUTTONDBLCLICK
, state
,
267 pressbind
=region_lookup_binding(reg
, BINDING_BUTTONPRESS
, state
,
271 if(pressbind
==NULL
&& sub
){
272 /* If subwindow doesn't listen to state/button(/area) at all, return and
273 * let the parent that has the event grabbed, handle it. Otherwise we
274 * fully block the parent.
276 if(!dblclick
&& !listens_to(reg
, state
, button
, area
))
281 p_motion_begin_handler
=NULL
;
282 p_motion_handler
=NULL
;
283 p_motion_end_handler
=NULL
;
285 p_killed_handler
=NULL
;
289 p_orig_x
=p_x
=ev
->x_root
;
290 p_orig_y
=p_y
=ev
->y_root
;
295 watch_setup(&p_regwatch
, (Obj
*)reg
, NULL
);
297 watch_setup(&p_subregwatch
, (Obj
*)subreg
, NULL
);
299 ioncore_grab_establish(reg
, handle_key
, pointer_grab_killed
, 0);
303 call_button(pressbind
, ev
);
309 bool ioncore_do_handle_buttonpress(XButtonEvent
*ev
)
311 /* Only one level of subwindows is supported... more would require
312 * searching through the trees thanks to grabbed events being reported
313 * relative to the outermost grabbing window.
315 if(ev
->subwindow
!=None
&& ev
->state
!=0){
316 XButtonEvent ev2
=*ev
;
317 ev2
.window
=ev
->subwindow
;
319 if(XTranslateCoordinates(ioncore_g
.dpy
, ev
->window
, ev2
.window
,
320 ev
->x
, ev
->y
, &(ev2
.x
), &(ev2
.y
),
322 if(ioncore_dodo_handle_buttonpress(&ev2
, TRUE
))
327 return ioncore_dodo_handle_buttonpress(ev
, FALSE
);
331 bool ioncore_do_handle_buttonrelease(XButtonEvent
*ev
)
333 WBinding
*binding
=NULL
;
335 if(p_button
!=ev
->button
)
341 binding
=region_lookup_binding(p_reg
, BINDING_BUTTONCLICK
,
342 p_state
, p_button
, p_area
);
344 call_button(binding
, ev
);
351 ioncore_grab_remove(handle_key
);
358 void ioncore_do_handle_motionnotify(XMotionEvent
*ev
)
361 WBinding
*binding
=NULL
;
367 if(motion_in_threshold(ev
->x_root
, ev
->y_root
))
369 binding
=region_lookup_binding(p_reg
, BINDING_BUTTONMOTION
,
370 p_state
, p_button
, p_area
);
380 call_motion_begin(binding
, ev
, dx
, dy
);
383 call_motion(ev
, dx
, dy
);