Spell 'serialize' with a 'z'
[notion.git] / ioncore / pointer.c
bloba63168f62887fffe7575a421e62105929afa6bb8
1 /*
2 * ion/ioncore/pointer.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include "common.h"
10 #include "pointer.h"
11 #include "cursor.h"
12 #include "event.h"
13 #include "global.h"
14 #include "focus.h"
15 #include "regbind.h"
16 #include "grab.h"
17 #include "xwindow.h"
20 /*{{{ Variables */
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;
28 static Time p_time=0;
29 static int p_area=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)
44 /*}}}*/
47 /*{{{ Handler setup */
50 bool ioncore_set_drag_handlers(WRegion *reg,
51 WMotionHandler *begin,
52 WMotionHandler *motion,
53 WButtonHandler *end,
54 GrabHandler *keypress,
55 GrabKilledHandler *killed)
57 if(ioncore_pointer_grab_region()==NULL || p_motion)
58 return FALSE;
60 /* A motion handler set at this point may not set a begin handler */
61 if(p_grabstate!=ST_HELD && begin!=NULL)
62 return FALSE;
64 if(p_reg!=reg){
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;
74 p_motion=TRUE;
76 return TRUE;
80 /*}}}*/
83 /*{{{ Misc. */
86 static bool time_in_threshold(Time time)
88 Time t;
90 if(time<p_time)
91 t=p_time-time;
92 else
93 t=time-p_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)
109 return NULL;
110 return p_reg;
114 /*}}}*/
117 /*{{{ Call handlers */
120 static XEvent *p_curr_event=NULL;
123 XEvent *ioncore_current_pointer_event()
125 return p_curr_event;
129 static void call_button(WBinding *binding, XButtonEvent *ev)
131 if(binding==NULL)
132 return;
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));
137 p_curr_event=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);
146 p_curr_event=NULL;
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);
156 p_curr_event=NULL;
161 static void call_motion_begin(WBinding *binding, XMotionEvent *ev,
162 int dx, int dy)
164 if(binding==NULL)
165 return;
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;
176 p_curr_event=NULL;
180 /*}}}*/
183 /*{{{ ioncore_handle_button_press/release/motion */
186 static void finish_pointer()
188 if(p_reg!=NULL)
189 window_release((WWindow*)p_reg);
190 p_grabstate=ST_NO;
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)){
199 finish_pointer();
200 return TRUE;
203 return FALSE;
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);
212 finish_pointer();
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;
221 int i;
223 for(i=0; i<n_acts; i++){
224 if(region_lookup_binding(reg, acts[i], state, button, area))
225 return TRUE;
228 return FALSE;
232 static bool ioncore_dodo_handle_buttonpress(XButtonEvent *ev, bool sub)
234 WBinding *pressbind=NULL;
235 WRegion *reg=NULL;
236 WRegion *subreg=NULL;
237 uint button, state;
238 bool dblclick;
239 int area;
241 state=ev->state;
242 button=ev->button;
244 reg=(WRegion*)XWINDOW_REGION_OF_T(ev->window, WWindow);
246 if(reg==NULL)
247 return FALSE;
249 dblclick=(p_clickcnt==1 && time_in_threshold(ev->time) &&
250 p_button==button && p_state==state);
252 if(dblclick && p_reg!=reg){
253 if(sub)
254 return FALSE;
255 dblclick=FALSE;
258 subreg=region_current(reg);
259 area=window_press((WWindow*)reg, ev, &subreg);
261 if(dblclick){
262 pressbind=region_lookup_binding(reg, BINDING_BUTTONDBLCLICK, state,
263 button, area);
266 if(pressbind==NULL){
267 pressbind=region_lookup_binding(reg, BINDING_BUTTONPRESS, state,
268 button, area);
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))
277 return FALSE;
280 p_motion=FALSE;
281 p_motion_begin_handler=NULL;
282 p_motion_handler=NULL;
283 p_motion_end_handler=NULL;
284 p_key_handler=NULL;
285 p_killed_handler=NULL;
286 p_grabstate=ST_INIT;
287 p_button=button;
288 p_state=state;
289 p_orig_x=p_x=ev->x_root;
290 p_orig_y=p_y=ev->y_root;
291 p_time=ev->time;
292 p_clickcnt=0;
293 p_area=area;
295 watch_setup(&p_regwatch, (Obj*)reg, NULL);
296 if(subreg!=NULL)
297 watch_setup(&p_subregwatch, (Obj*)subreg, NULL);
299 ioncore_grab_establish(reg, handle_key, pointer_grab_killed, 0);
300 p_grabstate=ST_HELD;
302 if(pressbind!=NULL)
303 call_button(pressbind, ev);
305 return TRUE;
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;
318 ev2.subwindow=None;
319 if(XTranslateCoordinates(ioncore_g.dpy, ev->window, ev2.window,
320 ev->x, ev->y, &(ev2.x), &(ev2.y),
321 &(ev2.subwindow))){
322 if(ioncore_dodo_handle_buttonpress(&ev2, TRUE))
323 return 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)
336 return FALSE;
338 if(p_reg!=NULL){
339 if(p_motion==FALSE){
340 p_clickcnt=1;
341 binding=region_lookup_binding(p_reg, BINDING_BUTTONCLICK,
342 p_state, p_button, p_area);
343 if(binding!=NULL)
344 call_button(binding, ev);
345 }else{
346 call_motion_end(ev);
351 ioncore_grab_remove(handle_key);
352 finish_pointer();
354 return TRUE;
358 void ioncore_do_handle_motionnotify(XMotionEvent *ev)
360 int dx, dy;
361 WBinding *binding=NULL;
363 if(p_reg==NULL)
364 return;
366 if(!p_motion){
367 if(motion_in_threshold(ev->x_root, ev->y_root))
368 return;
369 binding=region_lookup_binding(p_reg, BINDING_BUTTONMOTION,
370 p_state, p_button, p_area);
373 p_time=ev->time;
374 dx=ev->x_root-p_x;
375 dy=ev->y_root-p_y;
376 p_x=ev->x_root;
377 p_y=ev->y_root;
379 if(!p_motion){
380 call_motion_begin(binding, ev, dx, dy);
381 p_motion=TRUE;
382 }else{
383 call_motion(ev, dx, dy);
388 /*}}}*/