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
)
136 p_curr_event
=(XEvent
*)ev
;
137 extl_call(binding
->func
, "ooo", NULL
, p_reg
, p_subreg
,
138 (p_reg
!=NULL
? p_reg
->active_sub
: NULL
));
143 static void call_motion(XMotionEvent
*ev
, int dx
, int dy
)
145 if(p_motion_handler
!=NULL
&& p_reg
!=NULL
){
146 p_curr_event
=(XEvent
*)ev
;
147 p_motion_handler(p_reg
, ev
, dx
, dy
);
153 static void call_motion_end(XButtonEvent
*ev
)
155 if(p_motion_end_handler
!=NULL
&& p_reg
!=NULL
){
156 p_curr_event
=(XEvent
*)ev
;
157 p_motion_end_handler(p_reg
, ev
);
163 static void call_motion_begin(WBinding
*binding
, XMotionEvent
*ev
,
171 p_curr_event
=(XEvent
*)ev
;
173 extl_call(binding
->func
, "oo", NULL
, p_reg
, p_subreg
);
175 if(p_motion_begin_handler
!=NULL
&& p_reg
!=NULL
)
176 p_motion_begin_handler(p_reg
, ev
, dx
, dy
);
178 p_motion_begin_handler
=NULL
;
187 /*{{{ ioncore_handle_button_press/release/motion */
190 static void finish_pointer()
193 window_release((WWindow
*)p_reg
);
195 watch_reset(&p_subregwatch
);
199 static bool handle_key(WRegion
*reg
, XEvent
*ev
)
201 if(p_key_handler
!=NULL
){
202 if(p_key_handler(reg
, ev
)){
211 static void pointer_grab_killed(WRegion
*unused
)
213 if(p_reg
!=NULL
&& p_killed_handler
!=NULL
)
214 p_killed_handler(p_reg
);
215 watch_reset(&p_regwatch
);
220 static bool listens_to(WRegion
*reg
, uint state
, uint button
, int area
)
222 static const int acts
[]={BINDING_BUTTONMOTION
, BINDING_BUTTONCLICK
,
223 BINDING_BUTTONDBLCLICK
};
224 static const int n_acts
=3;
227 for(i
=0; i
<n_acts
; i
++){
228 if(region_lookup_binding(reg
, acts
[i
], state
, button
, area
))
236 static bool ioncore_dodo_handle_buttonpress(XButtonEvent
*ev
, bool sub
)
238 WBinding
*pressbind
=NULL
;
240 WRegion
*subreg
=NULL
;
248 reg
=(WRegion
*)XWINDOW_REGION_OF_T(ev
->window
, WWindow
);
253 dblclick
=(p_clickcnt
==1 && time_in_threshold(ev
->time
) &&
254 p_button
==button
&& p_state
==state
);
256 if(dblclick
&& p_reg
!=reg
){
262 subreg
=region_current(reg
);
263 area
=window_press((WWindow
*)reg
, ev
, &subreg
);
266 pressbind
=region_lookup_binding(reg
, BINDING_BUTTONDBLCLICK
, state
,
271 pressbind
=region_lookup_binding(reg
, BINDING_BUTTONPRESS
, state
,
275 if(pressbind
==NULL
&& sub
){
276 /* If subwindow doesn't listen to state/button(/area) at all, return and
277 * let the parent that has the event grabbed, handle it. Otherwise we
278 * fully block the parent.
280 if(!dblclick
&& !listens_to(reg
, state
, button
, area
))
285 p_motion_begin_handler
=NULL
;
286 p_motion_handler
=NULL
;
287 p_motion_end_handler
=NULL
;
289 p_killed_handler
=NULL
;
293 p_orig_x
=p_x
=ev
->x_root
;
294 p_orig_y
=p_y
=ev
->y_root
;
299 watch_setup(&p_regwatch
, (Obj
*)reg
, NULL
);
301 watch_setup(&p_subregwatch
, (Obj
*)subreg
, NULL
);
303 ioncore_grab_establish(reg
, handle_key
, pointer_grab_killed
, 0);
307 call_button(pressbind
, ev
);
313 bool ioncore_do_handle_buttonpress(XButtonEvent
*ev
)
315 /* Only one level of subwindows is supported... more would require
316 * searching through the trees thanks to grabbed events being reported
317 * relative to the outermost grabbing window.
319 if(ev
->subwindow
!=None
&& ev
->state
!=0){
320 XButtonEvent ev2
=*ev
;
321 ev2
.window
=ev
->subwindow
;
323 if(XTranslateCoordinates(ioncore_g
.dpy
, ev
->window
, ev2
.window
,
324 ev
->x
, ev
->y
, &(ev2
.x
), &(ev2
.y
),
326 if(ioncore_dodo_handle_buttonpress(&ev2
, TRUE
))
331 return ioncore_dodo_handle_buttonpress(ev
, FALSE
);
335 bool ioncore_do_handle_buttonrelease(XButtonEvent
*ev
)
337 WBinding
*binding
=NULL
;
339 if(p_button
!=ev
->button
)
345 binding
=region_lookup_binding(p_reg
, BINDING_BUTTONCLICK
,
346 p_state
, p_button
, p_area
);
348 call_button(binding
, ev
);
355 ioncore_grab_remove(handle_key
);
362 void ioncore_do_handle_motionnotify(XMotionEvent
*ev
)
365 WBinding
*binding
=NULL
;
371 if(motion_in_threshold(ev
->x_root
, ev
->y_root
))
373 binding
=region_lookup_binding(p_reg
, BINDING_BUTTONMOTION
,
374 p_state
, p_button
, p_area
);
384 call_motion_begin(binding
, ev
, dx
, dy
);
387 call_motion(ev
, dx
, dy
);