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