1 /* +-------------------------------------------------------------------+ */
2 /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
3 /* |                                                                   | */
4 /* | Permission to use, copy, modify, and to distribute this software  | */
5 /* | and its documentation for any purpose is hereby granted without   | */
6 /* | fee, provided that the above copyright notice appear in all       | */
7 /* | copies and that both that copyright notice and this permission    | */
8 /* | notice appear in supporting documentation.  There is no           | */
9 /* | representations about the suitability of this software for        | */
10 /* | any purpose.  this software is provided "as is" without express   | */
11 /* | or implied warranty.                                              | */
12 /* |                                                                   | */
13 /* +-------------------------------------------------------------------+ */
14 
15 /* $Id: PaintEvent.c,v 1.17 2005/03/20 20:15:32 demailly Exp $ */
16 
17 #include <stdlib.h>
18 #include <X11/StringDefs.h>
19 #include <X11/IntrinsicP.h>
20 #include "PaintP.h"
21 #include "xpaint.h"
22 
23 extern void PopdownMenusGlobal();
24 extern int getIndexOp();
25 extern void DelimitationAction(int x, int y);
26 
27 typedef void (*func_t) (Widget, void *, XEvent *, OpInfo *);
28 
29 typedef struct data_s {
30     Widget w;
31     func_t func;
32     void *data;
33     int mask, flag;
34     int surfMask;
35     struct data_s *next;
36     OpInfo *info;
37 } data_t;
38 
39 static data_t *list = NULL;
40 
41 #if 0
42 static data_t **
43 widgetEvent(Widget w, data_t * look)
44 {
45     static data_t *d[10];
46     data_t *cur = list;
47     int n = 0;
48 
49     while (cur != NULL) {
50 	if (cur->mask == look->mask &&
51 	    cur->flag == look->flag &&
52 	    cur->func == look->func &&
53 	    cur->w == w)
54 	    d[n++] = cur;
55 	cur = cur->next;
56     }
57 
58     d[n] = NULL;
59 
60     return n == 0 ? NULL : d;
61 }
62 #endif
63 
64 #define FROM_BELOW 1
65 #if FROM_BELOW
66 #define APPROX(u,m) (((u)/(m))*(m))
67 #else
68 #define APPROX(u,m) ((((u)+(m)/2)/(m))*(m))
69 #endif
70 
71 static void
opHandleEvent(Widget w,XtPointer dataArg,XEvent * event,Boolean * junk)72 opHandleEvent(Widget w, XtPointer dataArg, XEvent * event, Boolean * junk)
73 {
74     data_t *data = (data_t *) dataArg;
75     int snap_x, snap_y;
76     PaintWidget paint = (PaintWidget) w;
77     OpInfo *info = data->info;
78     static Window lastWindow = None;
79     static Display *lastDisplay = None;
80     static int lastType;
81     static int lastX, lastY;
82     Boolean same;
83     Position x, y;
84     Dimension wd, ht;
85     int zoom;
86 
87     if (Global.popped_up) {
88         if (event->type == ButtonRelease) {
89 	    XtVaGetValues(Global.popped_up,
90                           XtNx, &x, XtNy, &y,
91                           XtNwidth, &wd, XtNheight, &ht, NULL);
92             x = event->xbutton.x_root - x;
93             y = event->xbutton.y_root - y;
94             if (x<0 || x>wd || y<0 || y>ht)
95                 PopdownMenusGlobal();
96         }
97         event->type = None;
98         return;
99     }
100 
101     XtVaGetValues((Widget)paint, XtNlocked, &same, NULL);
102     if (same) return;
103 #if 0
104     XEvent myEvent;
105 
106     memcpy(&myEvent, event, sizeof(XEvent));
107     event = &myEvent;
108 #endif
109 
110     /*
111     **  Figure out if there is a snap, either by
112     **   choice or by zooming
113      */
114 
115     if ((zoom = GET_ZOOM(paint)) == 0)
116 	zoom = 1;
117     info->zoom = zoom;
118     info->isFat = ((zoom = GET_ZOOM(paint)) != 1);
119     if (paint->paint.snapOn) {
120         if (zoom>0) {
121 	    snap_x = paint->paint.snap_x * zoom;
122 	    snap_y = paint->paint.snap_y * zoom;
123 	} else {
124 	    snap_x = paint->paint.snap_x / (-zoom);
125 	    snap_y = paint->paint.snap_y / (-zoom);
126 	}
127     } else {
128         if (zoom>0)
129             snap_x = snap_y = zoom;
130         else
131             snap_x = snap_y = 1;
132     }
133     if (snap_x == 0) snap_x = 1;
134     if (snap_y == 0) snap_y = 1;
135 
136     same = (event->xany.window == lastWindow) &&
137 	(event->xany.display == lastDisplay) &&
138 	(event->xany.type == lastType);
139     lastWindow = event->xany.window;
140     lastDisplay = event->xany.display;
141     lastType = event->xany.type;
142 
143     /*
144     **  Snap events to the snap
145      */
146     if (event->type == ButtonPress || event->type == ButtonRelease) {
147 	info->realX = event->xbutton.x;
148 	info->realY = event->xbutton.y;
149     } else if (event->type == MotionNotify) {
150 	info->realX = event->xmotion.x;
151 	info->realY = event->xmotion.y;
152     }
153 
154     if (Global.delimitation && Global.delimitation->paint == w) {
155         if (event->type == ButtonRelease)
156 	    DelimitationAction(info->realX, info->realY);
157         return;
158     }
159 
160     if (((event->type == ButtonPress) ||
161 	 (event->type == ButtonRelease) ||
162 	 (event->type == MotionNotify)) && (snap_x > 1 || snap_y > 1)) {
163 	switch (event->type) {
164 	case ButtonPress:
165 	case ButtonRelease:
166 	    event->xbutton.x = APPROX(event->xbutton.x, snap_x);
167 	    event->xbutton.y = APPROX(event->xbutton.y, snap_y);
168 	    if (same && lastX == event->xbutton.x && lastY == event->xbutton.y)
169 		return;
170 	    break;
171 	case MotionNotify:
172 	    event->xmotion.x = APPROX(event->xbutton.x, snap_x);
173 	    event->xmotion.y = APPROX(event->xbutton.y, snap_y);
174 	    if (same && lastX == event->xmotion.x && lastY == event->xmotion.y)
175 		return;
176 	    break;
177 	}
178 	lastX = event->xmotion.x;
179 	lastY = event->xmotion.y;
180     } else {
181 	lastX = lastY = -1;
182     }
183 
184     if (event->type == MotionNotify) {
185         if (zoom>0) {
186 	    info->x = (event->xmotion.x / zoom) + paint->paint.zoomX;
187 	    info->y = (event->xmotion.y / zoom) + paint->paint.zoomY;
188 	} else {
189 	    info->x = (event->xmotion.x * (-zoom) + (-zoom/2)) + paint->paint.zoomX;
190 	    info->y = (event->xmotion.y * (-zoom) + (-zoom/2)) + paint->paint.zoomY;
191 	}
192     } else if (event->type == ButtonPress || event->type == ButtonRelease) {
193         if (zoom>0) {
194 	    info->x = (event->xbutton.x / zoom) + paint->paint.zoomX;
195 	    info->y = (event->xbutton.y / zoom) + paint->paint.zoomY;
196 	} else {
197 	    info->x = (event->xbutton.x * (-zoom) + (-zoom/2)) + paint->paint.zoomX;
198 	    info->y = (event->xbutton.y * (-zoom) + (-zoom/2)) + paint->paint.zoomY;
199 	}
200     }
201     /*
202     **  In fatbits we can't tell the difference
203     **   between snapping and fat bits.
204      */
205     if (info->isFat) {
206 	info->realX = info->x;
207 	info->realY = info->y;
208     } else {
209 	info->realX = info->realX + paint->paint.zoomX;
210 	info->realY = info->realY + paint->paint.zoomY;
211     }
212 
213     /*
214     **  If this is button down, save it for reference
215      */
216     if (event->type == ButtonPress) {
217 	paint->paint.downX = info->realX;
218 	paint->paint.downY = info->realY;
219     }
220     if (paint->paint.paint != None) {
221 	PaintWidget pw = (PaintWidget) paint->paint.paint;
222 	info->base = pw->paint.sourcePixmap;
223     } else {
224 	info->base = paint->paint.sourcePixmap;
225     }
226 
227     if (data->surfMask & opWindow) {
228 #if FROM_BELOW
229 	int z = GET_ZOOM(paint) / 2;
230 
231 	if (z > 0) {
232 	    if (event->type == MotionNotify) {
233 		event->xmotion.x += z;
234 		event->xmotion.y += z;
235 	    } else if (event->type == ButtonPress || event->type == ButtonRelease) {
236 		event->xbutton.x += z;
237 		event->xbutton.y += z;
238 	    }
239 	}
240 #endif
241 	info->surface = opWindow;
242 	info->drawable = event->xany.window;
243 	data->func(w, data->data, event, info);
244     }
245     if (event->type == MotionNotify) {
246 	event->xmotion.x = info->x;
247 	event->xmotion.y = info->y;
248     } else if (event->type == ButtonPress || event->type == ButtonRelease) {
249 	event->xbutton.x = info->x;
250 	event->xbutton.y = info->y;
251     }
252     if (data->surfMask & opPixmap) {
253 	info->surface = opPixmap;
254 	info->drawable = GET_PIXMAP(paint);
255 	data->func(w, data->data, event, info);
256     }
257 }
258 
259 void
OpAddEventHandler(Widget w,int surfMask,int mask,Boolean flag,void (* func)(Widget,void *,XEvent *,OpInfo *),void * data)260 OpAddEventHandler(Widget w, int surfMask, int mask, Boolean flag,
261 	   void (*func) (Widget, void *, XEvent *, OpInfo *), void *data)
262 {
263     PaintWidget paint = (PaintWidget) w;
264     PaintWidget pp = (PaintWidget) paint->paint.paint;
265     data_t *new = (data_t *) XtMalloc(sizeof(data_t));
266     OpInfo *info;
267 
268     if (new == NULL)
269 	return;
270 
271     Global.operation = 1 << getIndexOp();
272     new->w = w;
273     new->func = func;
274     new->data = data;
275     new->mask = mask;
276     new->flag = flag;
277     new->surfMask = surfMask;
278 
279     info = new->info = (OpInfo *) XtMalloc(sizeof(OpInfo));
280     info->refCount = 1;
281     info->realX = 0;
282     info->realY = 0;
283 
284     /*
285     **  Now build the approprate info structure
286      */
287     if (pp == None) {
288 	/*
289 	** If this is a paint widget, this is easy
290 	 */
291 	info->first_gc = paint->paint.fgc;
292 	info->second_gc = paint->paint.sgc;
293 	info->base_gc = paint->paint.igc;
294     } else {
295 	/*
296 	** For a fatbits paint widget get paint information
297 	 */
298 	info->first_gc = pp->paint.fgc;
299 	info->second_gc = pp->paint.sgc;
300 	info->base_gc = pp->paint.igc;
301     }
302 
303     new->next = list;
304     list = new;
305 
306     XtAddEventHandler(w, mask, flag, opHandleEvent, (XtPointer) new);
307 }
308 
309 void
OpRemoveEventHandler(Widget w,int surfMask,int mask,Boolean flag,void (* func)(Widget,void *,XEvent *,OpInfo *),void * data)310 OpRemoveEventHandler(Widget w, int surfMask, int mask, Boolean flag,
311 	   void (*func) (Widget, void *, XEvent *, OpInfo *), void *data)
312 {
313     data_t *cur = list;
314     data_t **prev = &list;
315 
316     Global.operation = 0;
317 
318     while (cur != NULL) {
319 	if (cur->w == w &&
320 	    cur->data == data &&
321 	    cur->mask == mask &&
322 	    cur->flag == flag &&
323 	    cur->surfMask == surfMask &&
324 	    cur->func == func)
325 	    break;
326 	prev = &cur->next;
327 	cur = cur->next;
328     }
329 
330     if (cur == NULL)
331 	return;
332 
333     XtRemoveEventHandler(w, mask, flag, opHandleEvent, (XtPointer) cur);
334 
335     *prev = cur->next;
336 
337     cur->info->refCount--;
338     if (cur->info->refCount == 0)
339 	XtFree((XtPointer) cur->info);
340 
341     XtFree((XtPointer) cur);
342 }
343