1 /*  Part of XPCE --- The SWI-Prolog GUI toolkit
2 
3     Author:        Jan Wielemaker and Anjo Anjewierden
4     E-mail:        jan@swi.psy.uva.nl
5     WWW:           http://www.swi.psy.uva.nl/projects/xpce/
6     Copyright (c)  1985-2002, University of Amsterdam
7     All rights reserved.
8 
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions
11     are met:
12 
13     1. Redistributions of source code must retain the above copyright
14        notice, this list of conditions and the following disclaimer.
15 
16     2. Redistributions in binary form must reproduce the above copyright
17        notice, this list of conditions and the following disclaimer in
18        the documentation and/or other materials provided with the
19        distribution.
20 
21     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25     COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32     POSSIBILITY OF SUCH DAMAGE.
33 */
34 
35 #include <h/kernel.h>
36 #include <h/graphics.h>
37 #include <time.h>
38 
39 forwards void init_event_tree(void);
40 
41 extern EventNodeObj getNodeEventTree(EventTreeObj t, Any value);
42 
43 #define TOINT(x) x
44 
45 static Int	 last_buttons     = TOINT(ZERO); /* defaults for next event */
46 static Any	 last_window      = NIL;
47 static Int	 last_x		  = TOINT(ZERO);
48 static Int	 last_y		  = TOINT(ZERO);
49 static unsigned long last_time	  = 0L;
50 
51 static Int	         last_down_bts    = ZERO;
52 static int	         last_down_x      = -1000; /* multiclick detection */
53 static int	         last_down_y	  = -1000;
54 static unsigned long     last_down_time   = 0;
55 static unsigned int	 multi_click_time = 400;
56 static int	         multi_click_diff = 4;
57 static int	         last_click_type  = CLICK_TYPE_triple;
58 static int		 loc_still_posted = TRUE;
59 static unsigned long	 host_last_time   = 0;
60 static int		 loc_still_time	  = 400;
61 
62 static status
initialiseEvent(EventObj e,Name id,Any window,Int x,Int y,Int bts,Int time)63 initialiseEvent(EventObj e, Name id, Any window,
64 		Int x, Int y, Int bts, Int time)
65 { unsigned long t = valInt(time);
66 
67   initialiseProgramObject(e);
68 
69   if ( notNil(EVENT->value) )
70   { EventObj parent = EVENT->value;
71 
72     if ( isDefault(x) )      x      = parent->x;
73     if ( isDefault(y) )      y      = parent->y;
74     if ( isDefault(bts) )    bts    = parent->buttons;
75     if ( isDefault(window) ) window = parent->window;
76     if ( isDefault(time) )   t      = max(last_time, parent->time);
77   } else
78   { if ( isDefault(x) )      x      = last_x;
79     if ( isDefault(y) )      y      = last_y;
80     if ( isDefault(bts) )    bts    = last_buttons;
81     if ( isDefault(window) ) window = last_window;
82     if ( isDefault(time) )   t      = last_time;
83   }
84 
85   host_last_time = mclock();
86   last_time      = t;
87   last_buttons   = bts;			/* save these values */
88   last_x         = x;
89   last_y         = y;
90 
91   assign(e, window,	window);
92   assign(e, receiver,	window);
93   assign(e, id,		id);
94   assign(e, x,		x);
95   assign(e, y,		y);
96   assign(e, buttons,	bts);
97   e->time = t;
98 
99   if ( isDownEvent(e) )
100   { int clt = CLICK_TYPE_single;
101     int px  = valInt(x);
102     int py  = valInt(y);
103 
104     DEBUG(NAME_multiclick, Cprintf("t: %ld (%ld), x: %d (%d), y: %d (%d) --> ",
105 				   t, last_down_time, px, last_down_x,
106 				   py, last_down_y));
107 
108     if ( (valInt(e->buttons) & CLICK_TYPE_mask) == CLICK_TYPE_double )
109     { switch( last_click_type )
110       { case CLICK_TYPE_single:	clt = CLICK_TYPE_double; break;
111 	case CLICK_TYPE_double:	clt = CLICK_TYPE_triple; break;
112 	default:		clt = CLICK_TYPE_single; break;
113       }
114       e->buttons = toInt(valInt(e->buttons) & ~CLICK_TYPE_mask);
115     } else
116     { if ( (t - last_down_time) < multi_click_time &&
117 	   abs(last_down_x - px) <= multi_click_diff &&
118 	   abs(last_down_y - py) <= multi_click_diff &&
119 	   (valInt(last_down_bts)&BUTTON_mask) == (valInt(bts)&BUTTON_mask) &&
120 	   last_window == window )
121       { switch( last_click_type )
122 	{ case CLICK_TYPE_single:	clt = CLICK_TYPE_double; break;
123 	  case CLICK_TYPE_double:	clt = CLICK_TYPE_triple; break;
124 	}
125       }
126     }
127 
128     last_click_type = clt;
129     assign(e, buttons, toInt(valInt(e->buttons) | clt));
130 
131     DEBUG(NAME_multiclick, Cprintf("%s\n", strName(getMulticlickEvent(e))));
132 
133     last_down_bts     = bts;
134     last_down_time    = t;
135     last_down_x       = px;
136     last_down_y       = py;
137   } else if ( isUpEvent(e) )
138   { assign(e, buttons, toInt(valInt(e->buttons) | last_click_type));
139   }
140 
141   if ( !onFlag(window, F_FREED|F_FREEING) )
142     last_window = window;
143 
144   if ( loc_still_posted )
145   { if ( isAEvent(e, NAME_locMove) )
146     { DEBUG(NAME_locStill, Cprintf("Re-enabled loc-still on %s\n", pp(e->id)));
147       loc_still_posted = FALSE;
148     }
149   } else if ( isAEvent(e, NAME_area) ||
150 	      isAEvent(e, NAME_deactivateKeyboardFocus) )
151   { DEBUG(NAME_locStill, Cprintf("Disabled loc-still on %s\n", pp(e->id)));
152     loc_still_posted = TRUE;
153   }
154 
155   succeed;
156 }
157 
158 		 /*******************************
159 		 *	    LOC-STILL		*
160 		 *******************************/
161 
162 void
considerLocStillEvent()163 considerLocStillEvent()
164 { if ( !loc_still_posted )
165   { unsigned long now = mclock();
166 
167     if ( now - host_last_time < (unsigned long)loc_still_time )
168     { DEBUG(NAME_locStill, Cprintf("TimeDiff = %d (ignored)\n", now - host_last_time));
169       return;
170     }
171 
172     if ( !pceMTTryLock(LOCK_PCE) )
173       return;
174     if ( instanceOfObject(last_window, ClassWindow) &&
175 	 !onFlag(last_window, F_FREED|F_FREEING) &&
176 	 valInt(last_x) > 0 && valInt(last_y) > 0 )
177     { ServiceMode(is_service_window(last_window),
178 		  { AnswerMark mark;
179 		    EventObj e;
180 
181 		    markAnswerStack(mark);
182 		    e = newObject(ClassEvent,
183 				  NAME_locStill, last_window,
184 				  last_x, last_y, last_buttons,
185 				  toInt(last_time + now - host_last_time), EAV);
186 		    addCodeReference(e);
187 		    postNamedEvent(e, (Graphical) last_window, DEFAULT, NAME_postEvent);
188 		    delCodeReference(e);
189 		    freeableObj(e);
190 		    rewindAnswerStack(mark, NIL);
191 		  })
192     }
193     loc_still_posted = TRUE;
194     pceMTUnlock(LOCK_PCE);
195   }
196 }
197 
198 
199 		 /*******************************
200 		 *	     WINDOW		*
201 		 *******************************/
202 
203 PceWindow
WindowOfLastEvent()204 WindowOfLastEvent()
205 { if ( !isProperObject(last_window) )
206   { Cprintf("Warning: last_window = %s\n", pp(last_window));
207     fail;
208   }
209 
210   if ( instanceOfObject(last_window, ClassWindow) )
211     return last_window;
212 
213   fail;
214 }
215 
216 
217 void
unlinkedWindowEvent(Any sw)218 unlinkedWindowEvent(Any sw)
219 { if ( sw == last_window )
220     last_window = NIL;
221 }
222 
223 
224 		/********************************
225 		*          CONVERSION		*
226 		********************************/
227 
228 static EventObj
getConvertEvent(Class class,Any def)229 getConvertEvent(Class class, Any def)
230 { if ( isDefault(def) && instanceOfObject(EVENT->value, ClassEvent) )
231     answer(EVENT->value);		/* @event */
232 
233   fail;
234 }
235 
236 
237 		/********************************
238 		*        TIME MANAGEMENT	*
239 		********************************/
240 
241 unsigned long				/* time-stamp of last event */
LastEventTime(void)242 LastEventTime(void)
243 { return last_time;
244 }
245 
246 
247 void
setLastEventTime(unsigned long time)248 setLastEventTime(unsigned long time)
249 { last_time = time;
250 }
251 
252 
253 static Int
getTimeEvent(EventObj ev,EventObj ev2)254 getTimeEvent(EventObj ev, EventObj ev2)
255 { if ( notDefault(ev2) )
256     answer(toInt(ev2->time - ev->time));
257   else
258     answer(toInt(ev->time % PCE_MAX_INT));
259 }
260 
261 
262 		/********************************
263 		*          EVENT_TYPES		*
264 		********************************/
265 
266 
267 status
isAEvent(EventObj e,Any id)268 isAEvent(EventObj e, Any id)
269 { Name nm;
270   EventNodeObj sb, super;
271 
272   if ( isInteger(id) )
273     return e->id == id ? SUCCEED : FAIL;
274 
275   if ( isInteger(e->id) )
276   { int c = valInt(e->id);
277 
278     if      ( c < 32 || c == 127 )		nm = NAME_control;
279     else if ( c >= 32 && c < META_OFFSET )	nm = NAME_printable;
280     else if ( c >= META_OFFSET   )		nm = NAME_meta;
281     else					fail;
282   } else if ( isName(e->id) )
283   { nm = e->id;
284   } else
285   { fail;
286   }
287 
288   TRY( sb    = getNodeEventTree(EventTree, nm) );
289   TRY( super = getNodeEventTree(EventTree, id) );
290 
291   return isAEventNode(sb, super);
292 }
293 
294 
295 status
eventName(Name name)296 eventName(Name name)
297 { if ( !EventTree )
298     realiseClass(ClassEvent);
299 
300   return getNodeEventTree(EventTree, name) ? SUCCEED : FAIL;
301 }
302 
303 		/********************************
304 		*             BUTTONS		*
305 		********************************/
306 
307 static status
allButtonsUpLastEvent(void)308 allButtonsUpLastEvent(void)
309 { if ( valInt(last_buttons) &
310        (BUTTON_ms_left|BUTTON_ms_middle|BUTTON_ms_right) )
311     fail;
312 
313   succeed;
314 }
315 
316 
317 status
allButtonsUpEvent(EventObj e)318 allButtonsUpEvent(EventObj e)
319 { if ( valInt(e->buttons) &
320        (BUTTON_ms_left|
321 	BUTTON_ms_middle|
322 	BUTTON_ms_right|
323 	BUTTON_ms_button4|
324 	BUTTON_ms_button5) )
325     fail;
326 
327   succeed;
328 }
329 
330 
331 status
isUpEvent(EventObj e)332 isUpEvent(EventObj e)
333 { if ( isName(e->id) && (equalName(e->id, NAME_msLeftUp) ||
334 			 equalName(e->id, NAME_msMiddleUp) ||
335 			 equalName(e->id, NAME_msRightUp) ||
336 			 equalName(e->id, NAME_msButton4Up) ||
337 			 equalName(e->id, NAME_msButton5Up)) )
338     succeed;
339   fail;
340 }
341 
342 
343 status
isDownEvent(EventObj e)344 isDownEvent(EventObj e)
345 { if ( isName(e->id) && (equalName(e->id, NAME_msLeftDown) ||
346 			 equalName(e->id, NAME_msMiddleDown) ||
347 			 equalName(e->id, NAME_msRightDown) ||
348 			 equalName(e->id, NAME_msButton4Down) ||
349 			 equalName(e->id, NAME_msButton5Down)) )
350     succeed;
351   fail;
352 }
353 
354 
355 Name
getButtonEvent(EventObj e)356 getButtonEvent(EventObj e)
357 { if ( isAEvent(e, NAME_msLeft) )
358     answer(NAME_left);
359   if ( isAEvent(e, NAME_msMiddle) )
360     answer(NAME_middle);
361   if ( isAEvent(e, NAME_msRight) )
362     answer(NAME_right);
363   if ( isAEvent(e, NAME_msButton4) )
364     answer(NAME_button4);
365   if ( isAEvent(e, NAME_msButton5) )
366     answer(NAME_button5);
367 
368   errorPce(e, NAME_noButtonEvent);
369   fail;
370 }
371 
372 
373 status
isDragEvent(EventObj ev)374 isDragEvent(EventObj ev)
375 { if ( isAEvent(ev, NAME_msLeftDrag) ||
376        isAEvent(ev, NAME_msMiddleDrag) ||
377        isAEvent(ev, NAME_msRightDrag) ||
378        isAEvent(ev, NAME_msButton4Drag) ||
379        isAEvent(ev, NAME_msButton5Drag) )
380     succeed;
381 
382   fail;
383 }
384 
385 
386 		/********************************
387 		*            MODIFIERS		*
388 		********************************/
389 
390 status
hasModifierEvent(EventObj ev,Modifier m)391 hasModifierEvent(EventObj ev, Modifier m)
392 {
393 #define DOWN(b) (valInt(ev->buttons) & b)
394 #define UP(b)   (!DOWN(b))
395   if ( notDefault(m->shift) &&
396        ((m->shift == NAME_down && UP(BUTTON_shift)) ||
397 	(m->shift == NAME_up   && DOWN(BUTTON_shift))) )
398     fail;
399   if ( notDefault(m->control) &&
400        ((m->control == NAME_down && UP(BUTTON_control)) ||
401 	(m->control == NAME_up   && DOWN(BUTTON_control))) )
402     fail;
403   if ( notDefault(m->meta) &&
404        ((m->meta == NAME_down && UP(BUTTON_meta)) ||
405 	(m->meta == NAME_up   && DOWN(BUTTON_meta))) )
406     fail;
407 #undef UP
408 #undef DOWN
409 
410   succeed;
411 }
412 
413 
414 Name
getMulticlickEvent(EventObj e)415 getMulticlickEvent(EventObj e)
416 { switch(valInt(e->buttons) & CLICK_TYPE_mask)
417   { case CLICK_TYPE_single:	answer(NAME_single);
418     case CLICK_TYPE_double:	answer(NAME_double);
419     case CLICK_TYPE_triple:	answer(NAME_triple);
420     default:			fail;
421   }
422 }
423 
424 
425 Int
getClickTimeEvent(EventObj e)426 getClickTimeEvent(EventObj e)
427 { answer(toInt(e->time - last_down_time));
428 
429   fail;
430 }
431 
432 
433 Int
getClickDisplacementEvent(EventObj e)434 getClickDisplacementEvent(EventObj e)
435 { int dx = valInt(e->x) - last_down_x;
436   int dy = valInt(e->y) - last_down_y;
437 
438   answer(toInt(isqrt(dx*dx + dy*dy)));
439 }
440 
441 
442 status
windowEvent(EventObj ev,PceWindow sw)443 windowEvent(EventObj ev, PceWindow sw)
444 { if ( ev->window != sw )
445   { int x, y;
446 
447     offset_windows(sw, ev->window, &x, &y);
448     assign(ev, x, toInt(valInt(ev->x) - x));
449     assign(ev, y, toInt(valInt(ev->y) - y));
450     assign(ev, window, sw);
451   }
452 
453   succeed;
454 }
455 
456 
457 		/********************************
458 		*            POSITIONS		*
459 		********************************/
460 
461 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
462 Find the position of an  event.  The `x'  and `y' fields  of the event
463 indicate  the   position  relative  to the   receiving  window.  These
464 functions allow you to find the position relative to:
465 
466 	Display		The display on which the event occurred
467 	Frame		The frame of the window
468 	Device		Relative to the origin of the device
469 	Graphical	Some graphical in the window in which the
470 			event occurred
471 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
472 
473 static void
get_xy_event_window(EventObj ev,PceWindow w,BoolObj area,int * rx,int * ry)474 get_xy_event_window(EventObj ev, PceWindow w, BoolObj area, int *rx, int *ry)
475 { int x, y;
476 
477   offset_windows(w, ev->window, &x, &y);
478 
479   if ( area == ON )
480   { *rx = valInt(ev->x) - x;
481     *ry = valInt(ev->y) - y;
482   } else
483   { offset_window(w, rx, ry);
484     *rx = valInt(ev->x) - x - *rx;
485     *ry = valInt(ev->y) - y - *ry;
486   }
487 }
488 
489 
490 static void
get_xy_event_frame(EventObj ev,FrameObj fr,int * rx,int * ry)491 get_xy_event_frame(EventObj ev, FrameObj fr, int *rx, int *ry)
492 { FrameObj fr2;
493   int frx, fry;
494 
495   get_xy_event_window(ev, ev->window, ON, rx, ry);
496   DEBUG(NAME_drag, Cprintf("At %d, %d to %s\n", *rx, *ry, pp(ev->window)));
497   frame_offset_window(ev->window, &fr2, &frx, &fry);
498   *rx += frx;
499   *ry += fry;
500   DEBUG(NAME_drag, Cprintf("At %d, %d to %s\n", *rx, *ry, pp(fr2)));
501 
502   if ( fr != fr2 )
503   { Area a1 = fr->area;			/* target frame area */
504     Area a2 = fr2->area;		/* area of frame from event */
505 
506     *rx += valInt(a2->x) - valInt(a1->x);
507     *ry += valInt(a2->y) - valInt(a1->y);
508   }
509 }
510 
511 
512 static void
get_xy_event_display(EventObj ev,DisplayObj d,int * rx,int * ry)513 get_xy_event_display(EventObj ev, DisplayObj d, int *rx, int *ry)
514 { FrameObj fr;
515   int frx, fry;
516 
517   get_xy_event_window(ev, ev->window, ON, rx, ry);
518   DEBUG(NAME_position, Cprintf("Ev at %d,%d relative to %s\n",
519 			       *rx, *ry, pp(ev->window)));
520   frame_offset_window(ev->window, &fr, &frx, &fry);
521   DEBUG(NAME_position, Cprintf("Frame offset: %d,%d\n", frx, fry));
522   *rx += frx + valInt(fr->area->x);
523   *ry += fry + valInt(fr->area->y);
524 }
525 
526 
527 static void
get_xy_event_device(EventObj ev,Device dev,int * rx,int * ry)528 get_xy_event_device(EventObj ev, Device dev, int *rx, int *ry)
529 { int ox, oy;
530   PceWindow sw = getWindowGraphical((Graphical) dev);
531 
532   if ( !sw )
533   { *rx = 0; *ry = 0;
534     return;				/* generate an error? */
535   }
536 
537   get_xy_event_window(ev, sw, OFF, rx, ry);
538   offsetDeviceGraphical(dev, &ox, &oy);
539   *rx -= ox + valInt(dev->offset->x);
540   *ry -= oy + valInt(dev->offset->y);
541 }
542 
543 
544 
545 static void
get_xy_event_graphical(EventObj ev,Graphical gr,int * rx,int * ry)546 get_xy_event_graphical(EventObj ev, Graphical gr, int *rx, int *ry)
547 { int ox, oy;
548   PceWindow sw = getWindowGraphical(gr);
549 
550   if ( !sw )
551     sw = ev->window;
552 
553   get_xy_event_window(ev, sw, OFF, rx, ry);
554   offsetDeviceGraphical(gr, &ox, &oy);
555   DEBUG(NAME_inside, Cprintf("At %d,%d: offset %s --> %s is %d,%d\n",
556 			     *rx, *ry,
557 			     pp(gr), pp(sw), ox, oy));
558   *rx -= ox + valInt(gr->area->x);
559   *ry -= oy + valInt(gr->area->y);
560 }
561 
562 
563 static void
get_xy_event_node(EventObj ev,Node node,int * rx,int * ry)564 get_xy_event_node(EventObj ev, Node node, int *rx, int *ry)
565 { get_xy_event_graphical(ev, node->image, rx, ry);
566 }
567 
568 
569 status
get_xy_event(EventObj ev,Any obj,BoolObj area,Int * rx,Int * ry)570 get_xy_event(EventObj ev, Any obj, BoolObj area, Int *rx, Int *ry)
571 { int x = 0, y = 0;
572 
573   if ( isNil(ev->window) || onFlag(ev->window, F_FREEING|F_FREED) )
574   { *rx = ev->x;
575     *ry = ev->y;
576     succeed;
577   } else if ( instanceOfObject(obj, ClassDisplay) )
578     get_xy_event_display(ev, obj, &x, &y);
579   else if ( instanceOfObject(obj, ClassFrame) )
580     get_xy_event_frame(ev, obj, &x, &y);
581   else if ( instanceOfObject(obj, ClassWindow) )
582     get_xy_event_window(ev, obj, area, &x, &y);
583   else if ( instanceOfObject(obj, ClassDevice) )
584     get_xy_event_device(ev, obj, &x, &y);
585   else if ( instanceOfObject(obj, ClassGraphical) )
586     get_xy_event_graphical(ev, obj, &x, &y);
587   else if ( instanceOfObject(obj, ClassNode) )
588     get_xy_event_node(ev, obj, &x, &y);
589   else
590   { *rx = ev->x;
591     *ry = ev->y;
592     succeed;
593   }
594 
595   if ( area == ON &&
596        instanceOfObject(obj, ClassDevice) &&
597        !instanceOfObject(obj, ClassWindow) )
598   { Device dev = (Device) ev->receiver;
599     x -= valInt(dev->area->x) - valInt(dev->offset->x);
600     y -= valInt(dev->area->y) - valInt(dev->offset->y);
601   }
602 
603   *rx = toInt(x);
604   *ry = toInt(y);
605 
606   succeed;
607 }
608 
609 
610 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
611 Return x-y coordinates of  Event.  Normally these  are relative to the
612 window  involved, with graphical supplied   they  are  relative to the
613 graphicals coordinate system.
614 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
615 
616 Point
getPositionEvent(EventObj ev,Any obj)617 getPositionEvent(EventObj ev, Any obj)
618 { Int x, y;
619 
620   if ( isDefault(obj) )
621     obj = ev->receiver;
622 
623   TRY( get_xy_event(ev, obj, OFF, &x, &y) );
624 
625   if ( isNil(ev->position) )
626     assign(ev, position, newObject(ClassPoint, x, y, EAV));
627   else
628     setPoint(ev->position, x, y);
629 
630   answer(ev->position);
631 }
632 
633 
634 Point
getAreaPositionEvent(EventObj ev,Graphical gr)635 getAreaPositionEvent(EventObj ev, Graphical gr)
636 { Int x, y;
637 
638   if ( isDefault(gr) )
639     gr = ev->receiver;
640 
641   TRY( get_xy_event(ev, gr, ON, &x, &y) );
642 
643   if ( isNil(ev->position) )
644     assign(ev, position, newObject(ClassPoint, x, y, EAV));
645   else
646     setPoint(ev->position, x, y);
647 
648   answer(ev->position);
649 }
650 
651 
652 Int
getXEvent(EventObj ev,Any obj)653 getXEvent(EventObj ev, Any obj)
654 { Int x, y;
655 
656   if ( isDefault(obj) )
657     obj = ev->receiver;
658   TRY( get_xy_event(ev, obj, OFF, &x, &y) );
659 
660   answer(x);
661 }
662 
663 
664 Int
getYEvent(EventObj ev,Any obj)665 getYEvent(EventObj ev, Any obj)
666 { Int x, y;
667 
668   if ( isDefault(obj) )
669     obj = ev->receiver;
670   TRY( get_xy_event(ev, obj, OFF, &x, &y) );
671 
672   answer(y);
673 }
674 
675 
676 status
insideEvent(EventObj ev,Graphical gr)677 insideEvent(EventObj ev, Graphical gr)
678 { Int x, y;
679 
680   if ( isDefault(gr) )
681     gr = ev->receiver;
682 
683   TRY( get_xy_event(ev, gr, ON, &x, &y) );
684   DEBUG(NAME_inside, Cprintf("Event at %d,%d on %s\n",
685 			     valInt(x), valInt(y), pp(gr)));
686   if ( instanceOfObject(gr, ClassWindow) )
687   { int vx, vy, vw, vh;
688     PceWindow sw = (PceWindow) gr;
689     int ex = valInt(x);
690     int ey = valInt(y);
691 
692     compute_window(sw, &vx, &vy, &vw, &vh);
693     if ( ex >= vx && ex <= vx+vw &&
694 	 ey >= vy && ey <= vy+vh )
695       succeed;
696 
697     fail;
698   }
699 
700   return inEventAreaGraphical(gr, add(gr->area->x, x), add(gr->area->y, y));
701 }
702 
703 
704 static Any
getInsideSubWindow(EventObj ev,Any root)705 getInsideSubWindow(EventObj ev, Any root)
706 { return ws_event_in_subwindow(ev, root);
707 }
708 
709 
710 Int
getDistanceEvent(EventObj ev1,EventObj ev2)711 getDistanceEvent(EventObj ev1, EventObj ev2)
712 { if ( ev1->window == ev2->window )
713   { int dx = valInt(ev1->x) - valInt(ev2->x);
714     int dy = valInt(ev1->y) - valInt(ev2->y);
715 
716     answer(toInt(isqrt(dx * dx + dy * dy)));
717   }
718 
719   fail;
720 }
721 
722 
723 		/********************************
724 		*         GET PARAMETERS        *
725 		********************************/
726 
727 Any
getIdEvent(EventObj ev)728 getIdEvent(EventObj ev)
729 { answer(ev->id);
730 }
731 
732 
733 Any
getReceiverEvent(EventObj ev)734 getReceiverEvent(EventObj ev)
735 { answer(ev->receiver);
736 }
737 
738 
739 static Name
getKeyEvent(EventObj ev)740 getKeyEvent(EventObj ev)
741 { answer(characterName(ev));
742 }
743 
744 
745 		/********************************
746 		*         POSTING EVENTS	*
747 		********************************/
748 
749 #define WindowOfEvent(ev) ((PceWindow)(ev)->window)
750 
751 status
postNamedEvent(EventObj ev,Graphical obj,Recogniser rec,Name method)752 postNamedEvent(EventObj ev, Graphical obj, Recogniser rec, Name method)
753 { Graphical old = ev->receiver;
754   status rval;
755 
756   addCodeReference(ev);
757 
758   DEBUG(NAME_post,
759 	if ( ev->id != NAME_locMove &&
760 	     !isDragEvent(ev) )
761 	{ if ( isDefault(rec) )
762 	    Cprintf("Posting %s to %s->%s\n",
763 		    pp(ev->id), pp(obj), pp(method));
764 	  else
765 	    Cprintf("Posting %s to %s->%s (focus on %s)\n",
766 		    pp(ev->id), pp(obj), pp(method), pp(rec));
767 	});
768 
769 
770   withLocalVars({ assignVar(EVENT, ev, NAME_local);
771 		  assign(ev, receiver, obj);
772 
773 		  rval = qadSendv(notDefault(rec) ? (Any)rec : (Any)obj,
774 				  method, 1, (Any *)&ev);
775 
776 		  if ( !isFreedObj(ev) && isObject(old) && !isFreedObj(old) )
777 		  { if ( rval &&
778 			 instanceOfObject(ev->window, ClassWindow) &&
779 			 isNil(WindowOfEvent(ev)->focus) &&
780 			 isDownEvent(ev) && !allButtonsUpLastEvent() &&
781 			 instanceOfObject(obj, ClassGraphical) &&
782 			 getWindowGraphical(obj) == WindowOfEvent(ev) )
783 		      focusWindow(ev->window, obj, NIL, DEFAULT,
784 				  getButtonEvent(ev));
785 		    assign(ev, receiver, old);
786 		  }
787 		});
788 
789   if ( !isFreedObj(ev) )
790     delCodeReference(ev);
791 
792   DEBUG(NAME_post,
793 	if ( ev->id != NAME_locMove &&
794 	     !isDragEvent(ev) )
795 	  Cprintf("--> post of %s to %s %s\n",
796 		  pp(ev->id), pp(obj), rval ? "succeeded" : "failed"));
797 
798   return rval;
799 }
800 
801 
802 status
postEvent(EventObj ev,Graphical obj,Recogniser rec)803 postEvent(EventObj ev, Graphical obj, Recogniser rec)
804 { return postNamedEvent(ev, obj, rec, NAME_event);
805 }
806 
807 
808 		/********************************
809 		*      REPORTING CONTEXT	*
810 		********************************/
811 
812 Any
getMasterEvent(EventObj ev)813 getMasterEvent(EventObj ev)
814 { answer(getMasterGraphical(ev->receiver));
815 }
816 
817 
818 		/********************************
819 		*         MISCELLANEOUS		*
820 		********************************/
821 
822 DisplayObj
getDisplayEvent(EventObj ev)823 getDisplayEvent(EventObj ev)
824 { if ( instanceOfObject(ev->window, ClassWindow) )
825     answer(getDisplayGraphical((Graphical) ev->window));
826   else
827     answer(((FrameObj)ev->window)->display);
828 }
829 
830 		 /*******************************
831 		 *	     SCROLLING		*
832 		 *******************************/
833 
834 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
835 Deal with scroll-mice in X11. Such  mice   normally  report the wheel as
836 Z-axis motion events. As very  few   applications  know  about this, the
837 X-server normally maps  these  to  the   pointer-buttons  4  and  5. The
838 function below is called from editor, list_browser and window.
839 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
840 
841 status
mapWheelMouseEvent(EventObj ev,Any rec)842 mapWheelMouseEvent(EventObj ev, Any rec)
843 { if ( ev->id == NAME_wheel )
844   { Name dir, unit;
845     Int count;
846     Int rot = getAttributeObject(ev, NAME_rotation);
847 
848     if ( !rot )
849       fail;				/* Error? */
850 
851     if ( isDefault(rec) )
852       rec = ev->receiver;
853 
854     DEBUG(NAME_wheel,
855 	  Cprintf("mapWheelMouseEvent() on %s, rot=%s\n", pp(rec), pp(rot)));
856 
857     if ( !hasSendMethodObject(rec, NAME_scrollVertical) )
858       fail;
859 
860     if ( valInt(rot) > 0 )
861       dir = NAME_backwards;
862     else
863       dir = NAME_forwards;
864 
865     if ( valInt(ev->buttons) & BUTTON_shift )
866     { unit = NAME_line;
867       count = toInt(1);
868     } else if ( valInt(ev->buttons) & BUTTON_control )
869     { unit = NAME_page;
870       count = toInt(990);
871     } else
872     { unit = NAME_page;
873       count = toInt(200);
874     }
875 
876     send(rec, NAME_scrollVertical, dir, unit, count, EAV);
877     succeed;				/* Or return? */
878   }
879 
880   fail;
881 }
882 
883 
884 		 /*******************************
885 		 *	 CLASS DECLARATION	*
886 		 *******************************/
887 
888 /* Type declarations */
889 
890 static char *T_initialise[] =
891         { "id=event_id", "origin=[window|frame]", "x=[int]", "y=[int]", "button_mask=[int]", "time=[int]" };
892 static char *T_post[] =
893         { "to=graphical", "recogniser=[recogniser]" };
894 
895 /* Instance Variables */
896 
897 static vardecl var_event[] =
898 { IV(NAME_window, "window|frame", IV_GET,
899      NAME_context, "Window that generated event"),
900   IV(NAME_receiver, "graphical|frame", IV_GET,
901      NAME_context, "Object receiving event"),
902   IV(NAME_id, "event_id", IV_GET,
903      NAME_name, "Id of the event (type of event)"),
904   IV(NAME_buttons, "mask=int", IV_GET,
905      NAME_classify, "Bitmask with status of buttons"),
906   IV(NAME_x, "pixels=int", IV_GET,
907      NAME_position, "X-coordinate, relative to window"),
908   IV(NAME_y, "pixels=int", IV_GET,
909      NAME_position, "Y-coordinate, relative to window"),
910   IV(NAME_position, "point*", IV_NONE,
911      NAME_position, "Last calculated position"),
912   IV(NAME_time, "alien:Time", IV_NONE,
913      NAME_timing, "Window System Time stamp")
914 };
915 
916 /* Send Methods */
917 
918 static senddecl send_event[] =
919 { SM(NAME_initialise, 6, T_initialise, initialiseEvent,
920      DEFAULT, "Create from type, window, x, y, buttons and time"),
921   SM(NAME_hasModifier, 1, "modifier", hasModifierEvent,
922      NAME_classify, "Test if event meets modifier spec"),
923   SM(NAME_isA, 1, "super=event_id", isAEvent,
924      NAME_classify, "Test if event matches type identifier"),
925   SM(NAME_isDown, 0, NULL, isDownEvent,
926      NAME_classify, "Test if event is a button-down event"),
927   SM(NAME_isDrag, 0, NULL, isDragEvent,
928      NAME_classify, "Test if event is a button-drag event"),
929   SM(NAME_isUp, 0, NULL, isUpEvent,
930      NAME_classify, "Test if event is a button-up event"),
931   SM(NAME_post, 2, T_post, postEvent,
932      NAME_forward, "Deliver the event at the argument"),
933   SM(NAME_inside, 1, "[graphical]", insideEvent,
934      NAME_position, "Test if event is in area of graphical")
935 };
936 
937 /* Get Methods */
938 
939 static getdecl get_event[] =
940 { GM(NAME_convert, 1, "event", "[any]", getConvertEvent,
941      DEFAULT, "Convert @default into current event (@event)"),
942   GM(NAME_time, 1, "int", "[event]", getTimeEvent,
943      DEFAULT, "Timestamp (relative to argument)"),
944   GM(NAME_distance, 1, "int", "to=event", getDistanceEvent,
945      NAME_calculate, "Rounded integer distance between events"),
946   GM(NAME_button, 0, "button_name", NULL, getButtonEvent,
947      NAME_classify, "Button-name of button-event"),
948   GM(NAME_clickDisplacement, 0, "pixels=int", NULL, getClickDisplacementEvent,
949      NAME_classify, "`up' events: distance since corresponding `down'"),
950   GM(NAME_clickTime, 0, "milliseconds=int", NULL, getClickTimeEvent,
951      NAME_classify, "`up' events: time since corresponding `down'"),
952   GM(NAME_key, 0, "name", NULL, getKeyEvent,
953      NAME_classify, "Key(-binding) description of event"),
954   GM(NAME_multiclick, 0, "{single,double,triple}", NULL, getMulticlickEvent,
955      NAME_classify, "Click type"),
956   GM(NAME_display, 0, "display", NULL, getDisplayEvent,
957      NAME_context, "Display on which the event occurred"),
958   GM(NAME_master, 0, "any", NULL, getMasterEvent,
959      NAME_context, "The <-master of <-receiver"),
960   GM(NAME_name, 0, "event_id", NULL, getIdEvent,
961      NAME_name, "Name of the event (synonym for <-id)"),
962   GM(NAME_areaPosition, 1, "point", "relative_to=[graphical]", getAreaPositionEvent,
963      NAME_position, "Position relative to top-left-corner"),
964   GM(NAME_insideSubWindow, 1, "frame|window", "[display|frame|window]", getInsideSubWindow,
965      NAME_position, "Frame or window event occurred in"),
966   GM(NAME_position, 1, "point", "relative_to=[graphical|frame|display]", getPositionEvent,
967      NAME_position, "Position relative to argument"),
968   GM(NAME_x, 1, "int", "relative_to=[graphical|frame|display]", getXEvent,
969      NAME_position, "X coordinate relative to argument"),
970   GM(NAME_y, 1, "int", "relative_to=[graphical|frame|display]", getYEvent,
971      NAME_position, "Y coordinate relative to argument")
972 };
973 
974 /* Resources */
975 
976 static classvardecl rc_event[] =
977 { RC(NAME_x11WheelMouse, "bool", UXWIN("@on", "@off"),
978      "Enable/disable wheel-mouse emulation on button 4 and 5"),
979   RC(NAME_locStillTime, "int", "400",
980      "Time before generating a loc_still event in milliseconds")
981 };
982 
983 /* Class Declaration */
984 
985 static Name event_termnames[] = { NAME_receiver, NAME_name, NAME_position, NAME_buttons, NAME_time };
986 
987 ClassDecl(event_decls,
988           var_event, send_event, get_event, rc_event,
989           3, event_termnames,
990           "$Rev$");
991 
992 
993 status
makeClassEvent(Class class)994 makeClassEvent(Class class)
995 { Int t;
996 
997   declareClass(class, &event_decls);
998   cloneStyleVariableClass(class, NAME_receiver, NAME_reference);
999   cloneStyleVariableClass(class, NAME_window,   NAME_reference);
1000   init_event_tree();
1001 
1002   if ( (t=getClassVariableValueClass(class, NAME_locStillTime)) )
1003     loc_still_time = valInt(t);
1004 
1005   succeed;
1006 }
1007 
1008 
1009 static struct namepair
1010 { Name son;
1011   Name parent;
1012 } initial_tree[] =
1013 { { NAME_mouse,		NAME_any },
1014   { NAME_keyboard,	NAME_any },
1015   { NAME_user,		NAME_any },
1016 					/* Keyboard events */
1017   { NAME_ascii,		NAME_keyboard },
1018   { NAME_meta,		NAME_keyboard },
1019   { NAME_function,	NAME_keyboard },
1020   { NAME_control,	NAME_ascii },
1021   { NAME_printable,	NAME_ascii },
1022   { NAME_keyLeft,	NAME_function },
1023   { NAME_keyRight,	NAME_function },
1024   { NAME_keyTop,	NAME_function },
1025   { NAME_cursor,	NAME_function },
1026   { NAME_namedFunction, NAME_function },
1027   { NAME_keyLeft_1,	NAME_keyLeft },
1028   { NAME_keyLeft_2,	NAME_keyLeft },
1029   { NAME_keyLeft_3,	NAME_keyLeft },
1030   { NAME_keyLeft_4,	NAME_keyLeft },
1031   { NAME_keyLeft_5,	NAME_keyLeft },
1032   { NAME_keyLeft_6,	NAME_keyLeft },
1033   { NAME_keyLeft_7,	NAME_keyLeft },
1034   { NAME_keyLeft_8,	NAME_keyLeft },
1035   { NAME_keyLeft_9,	NAME_keyLeft },
1036   { NAME_keyLeft_10,	NAME_keyLeft },
1037   { NAME_keyRight_1,	NAME_keyRight },
1038   { NAME_keyRight_2,	NAME_keyRight },
1039   { NAME_keyRight_3,	NAME_keyRight },
1040   { NAME_keyRight_4,	NAME_keyRight },
1041   { NAME_keyRight_5,	NAME_keyRight },
1042   { NAME_keyRight_6,	NAME_keyRight },
1043   { NAME_keyRight_7,	NAME_keyRight },
1044   { NAME_keyRight_8,	NAME_keyRight },
1045   { NAME_keyRight_9,	NAME_keyRight },
1046   { NAME_keyRight_10,	NAME_keyRight },
1047   { NAME_keyRight_11,	NAME_keyRight },
1048   { NAME_keyRight_12,	NAME_keyRight },
1049   { NAME_keyRight_13,	NAME_keyRight },
1050   { NAME_keyRight_14,	NAME_keyRight },
1051   { NAME_keyRight_15,	NAME_keyRight },
1052   { NAME_keyTop_1,	NAME_keyTop },
1053   { NAME_keyTop_2,	NAME_keyTop },
1054   { NAME_keyTop_3,	NAME_keyTop },
1055   { NAME_keyTop_4,	NAME_keyTop },
1056   { NAME_keyTop_5,	NAME_keyTop },
1057   { NAME_keyTop_6,	NAME_keyTop },
1058   { NAME_keyTop_7,	NAME_keyTop },
1059   { NAME_keyTop_8,	NAME_keyTop },
1060   { NAME_keyTop_9,	NAME_keyTop },
1061   { NAME_keyTop_10,	NAME_keyTop },
1062 					/* Mouse button events */
1063   { NAME_button,	NAME_mouse },
1064   { NAME_wheel,		NAME_mouse },
1065   { NAME_msLeft,	NAME_button },
1066   { NAME_msMiddle,	NAME_button },
1067   { NAME_msRight,	NAME_button },
1068   { NAME_msButton4,	NAME_button },
1069   { NAME_msButton5,	NAME_button },
1070   { NAME_msLeftDown,	NAME_msLeft },
1071   { NAME_msLeftUp,	NAME_msLeft },
1072   { NAME_msLeftDrag,	NAME_msLeft },
1073   { NAME_msRightDown,	NAME_msRight },
1074   { NAME_msRightUp,	NAME_msRight },
1075   { NAME_msRightDrag,	NAME_msRight },
1076   { NAME_msMiddleDown,	NAME_msMiddle },
1077   { NAME_msMiddleUp,	NAME_msMiddle },
1078   { NAME_msMiddleDrag,	NAME_msMiddle },
1079   { NAME_msButton4Down,	NAME_msButton4 },
1080   { NAME_msButton4Up,	NAME_msButton4 },
1081   { NAME_msButton4Drag,	NAME_msButton4 },
1082   { NAME_msButton5Down,	NAME_msButton5 },
1083   { NAME_msButton5Up,	NAME_msButton5 },
1084   { NAME_msButton5Drag,	NAME_msButton5 },
1085 
1086 
1087   { NAME_select,	NAME_namedFunction },
1088   { NAME_print,		NAME_namedFunction },
1089   { NAME_execute,	NAME_namedFunction },
1090   { NAME_insert,	NAME_namedFunction },
1091   { NAME_undo,		NAME_namedFunction },
1092   { NAME_redo,		NAME_namedFunction },
1093   { NAME_menu,		NAME_namedFunction },
1094   { NAME_find,		NAME_namedFunction },
1095   { NAME_cancel,	NAME_namedFunction },
1096   { NAME_help,		NAME_namedFunction },
1097   { NAME_break,		NAME_namedFunction },
1098   { NAME_pause,		NAME_namedFunction },
1099   { NAME_backspace,	NAME_namedFunction },
1100 
1101   { NAME_cursorHome,	NAME_cursor },
1102   { NAME_cursorLeft,	NAME_cursor },
1103   { NAME_cursorRight,	NAME_cursor },
1104   { NAME_cursorUp,	NAME_cursor },
1105   { NAME_cursorDown,	NAME_cursor },
1106   { NAME_pageUp,	NAME_cursor },
1107   { NAME_pageDown,	NAME_cursor },
1108   { NAME_begin,		NAME_cursor },
1109   { NAME_end,		NAME_cursor },
1110 
1111   { NAME_area,		NAME_mouse },
1112   { NAME_areaEnter,	NAME_area },
1113   { NAME_areaExit,	NAME_area },
1114   { NAME_areaCancel,	NAME_areaExit },
1115   { NAME_areaResume,	NAME_areaEnter },
1116 
1117   { NAME_position,	NAME_mouse },
1118   { NAME_locMove,	NAME_position },
1119   { NAME_locStill,	NAME_position },
1120 
1121   { NAME_focus,				NAME_any },
1122   { NAME_deactivateKeyboardFocus,	NAME_focus },
1123   { NAME_releaseKeyboardFocus,		NAME_deactivateKeyboardFocus },
1124   { NAME_obtainKeyboardFocus,		NAME_focus },
1125   { NAME_activateKeyboardFocus,		NAME_obtainKeyboardFocus },
1126   { NAME_releaseFocus,			NAME_focus },
1127   { NAME_obtainFocus,			NAME_focus },
1128 
1129   { 0,			0 }
1130 };
1131 
1132 
1133 static void
add_node(Name n,Name super)1134 add_node(Name n, Name super)
1135 { EventNodeObj sn = getNodeEventTree(EventTree, super);
1136   EventNodeObj s  = newObject(ClassEventNode, n, EAV);
1137 
1138   send(sn, NAME_son, s, EAV);
1139 }
1140 
1141 
1142 static void
init_event_tree(void)1143 init_event_tree(void)
1144 { struct namepair *np;
1145 
1146   EventTree = globalObject(NAME_eventTree, ClassEventTree, EAV);
1147 
1148   send(EventTree, NAME_root, newObject(ClassEventNode, NAME_any, EAV), EAV);
1149 
1150   for(np = initial_tree; np->son; np++)
1151     add_node(np->son, np->parent);
1152 }
1153