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