1 
2 /* +-------------------------------------------------------------------+ */
3 /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)	       | */
4 /* | Copyright 1995, 1996 Torsten Martinsen (bullestock@dk-online.dk)  | */
5 /* |								       | */
6 /* | Permission to use, copy, modify, and to distribute this software  | */
7 /* | and its documentation for any purpose is hereby granted without   | */
8 /* | fee, provided that the above copyright notice appear in all       | */
9 /* | copies and that both that copyright notice and this permission    | */
10 /* | notice appear in supporting documentation.	 There is no	       | */
11 /* | representations about the suitability of this software for	       | */
12 /* | any purpose.  this software is provided "as is" without express   | */
13 /* | or implied warranty.					       | */
14 /* |								       | */
15 /* +-------------------------------------------------------------------+ */
16 
17 /* $Id: Paint.c,v 1.17 2005/03/20 20:15:32 demailly Exp $ */
18 
19 #include <X11/IntrinsicP.h>
20 #include <X11/StringDefs.h>
21 #include <X11/cursorfont.h>
22 #include <X11/ShellP.h>
23 #include <X11/Xatom.h>
24 #include <X11/Xft/Xft.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 
28 #include "PaintP.h"
29 #include "xpaint.h"
30 #include "image.h"
31 #include "misc.h"
32 
33 typedef void (*func_t) (Widget, void *, XEvent *, Boolean);
34 typedef struct data_s {
35     func_t func;
36     void *data;
37     int mask, flag;
38     struct data_s *next;
39 } data_t;
40 
41 void PwAddChild(Widget, Widget);
42 
43 static void pwSetPixmap(PaintWidget w, Pixmap pix, int flag);
44 static void fatCallback(Widget, XtPointer, XtPointer);
45 static void realExposeProc(PaintWidget, XExposeEvent *, Boolean);
46 
47 static XtResource resources[] =
48 {
49 #define offset(field) XtOffset(PaintWidget, paint.field)
50     /* {name, class, type, size, offset, default_type, default_addr}, */
51     {XtNcompress, XtCCompress, XtRBoolean, sizeof(Boolean),
52      offset(compress), XtRImmediate, (XtPointer) False},
53     {XtNreadOnly, XtCReadOnly, XtRBoolean, sizeof(Boolean),
54      offset(compress), XtRImmediate, (XtPointer) False},
55     {XtNdrawWidth, XtCDrawWidth, XtRInt, sizeof(int),
56      offset(drawWidth), XtRImmediate, (XtPointer) 512},
57     {XtNdrawHeight, XtCDrawHeight, XtRInt, sizeof(int),
58      offset(drawHeight), XtRImmediate, (XtPointer) 512},
59     {XtNlineWidth, XtCLineWidth, XtRInt, sizeof(int),
60      offset(lineWidth), XtRImmediate, (XtPointer) 0},
61     {XtNpattern, XtCPattern, XtRPixmap, sizeof(Pixmap),
62      offset(pattern), XtRPixmap, (XtPointer) None},
63     {XtNlinePattern, XtCLinePattern, XtRPixmap, sizeof(Pixmap),
64      offset(linePattern), XtRPixmap, (XtPointer) None},
65     {XtNpixmap, XtCPixmap, XtRPixmap, sizeof(Pixmap),
66      offset(sourcePixmap), XtRPixmap, (XtPointer) NULL},
67     {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
68      offset(foreground), XtRString, XtDefaultForeground},
69     {XtNlineForeground, XtCLineForeground, XtRPixel, sizeof(Pixel),
70      offset(lineForeground), XtRString, XtDefaultForeground},
71     {XtNmenubar, XtCMenubar, XtRBoolean, sizeof(Boolean),
72      offset(menubar), XtRImmediate, (XtPointer) True},
73     {XtNfullmenu, XtCFullMenu, XtRBoolean, sizeof(Boolean),
74      offset(fullmenu), XtRImmediate, (XtPointer) False},
75     {XtNgridmode, XtCGridMode, XtRInt, sizeof(int),
76      offset(gridmode), XtRImmediate, (XtPointer) (1<<31)},
77     {XtNinterpolation, XtCInterpolation, XtRInt, sizeof(int),
78      offset(interpolation), XtRImmediate, (XtPointer) 0},
79     {XtNtransparent, XtCTransparent, XtRInt, sizeof(int),
80      offset(transparent), XtRImmediate, (XtPointer) 1},
81     {XtNgridcolor, XtCGridColor, XtRPixel, sizeof(Pixel),
82      offset(gridcolor), XtRString, (XtPointer) "Green80"},
83     {XtNsnapX, XtCSnapX, XtRInt, sizeof(int),
84      offset(snap_x), XtRImmediate, (XtPointer) 10},
85     {XtNsnapY, XtCSnapY, XtRInt, sizeof(int),
86      offset(snap_y), XtRImmediate, (XtPointer) 10},
87     {XtNregionCallback, XtCRegionCallback, XtRCallback, sizeof(XtPointer),
88      offset(regionCalls), XtRCallback, (XtPointer) None},
89     {XtNsizeChanged, XtCSizeChanged, XtRCallback, sizeof(XtPointer),
90      offset(sizecalls), XtRCallback, (XtPointer) None},
91     {XtNfatBack, XtCFatBack, XtRCallback, sizeof(XtPointer),
92      offset(fatcalls), XtRCallback, (XtPointer) None},
93     {XtNundoSize, XtCUndoSize, XtRInt, sizeof(int),
94      offset(undoSize), XtRImmediate, (XtPointer) 1},
95     {XtNzoom, XtCZoom, XtRInt, sizeof(int),
96      offset(zoom), XtRImmediate, (XtPointer) 1},
97     {XtNzoomX, XtCZoomX, XtRInt, sizeof(int),
98      offset(zoomX), XtRImmediate, (XtPointer) 0},
99     {XtNzoomY, XtCZoomY, XtRInt, sizeof(int),
100      offset(zoomY), XtRImmediate, (XtPointer) 0},
101     {XtNgrid, XtCGrid, XtRBoolean, sizeof(Boolean),
102      offset(grid), XtRImmediate, (XtPointer) False},
103     {XtNsnapOn, XtCSnapOn, XtRBoolean, sizeof(Boolean),
104      offset(snapOn), XtRImmediate, (XtPointer) False},
105     {XtNpaint, XtCPaint, XtRWidget, sizeof(Widget),
106      offset(paint), XtRImmediate, (XtPointer) None},
107     {XtNdirty, XtCDirty, XtRBoolean, sizeof(Boolean),
108      offset(dirty), XtRImmediate, (XtPointer) False},
109     {XtNlocked, XtCLocked, XtRBoolean, sizeof(Boolean),
110      offset(locked), XtRImmediate, (XtPointer) False},
111     {XtNfillRule, XtCFillRule, XtRInt, sizeof(int),
112      offset(fillRule), XtRImmediate, (XtPointer) FillSolid},
113     {XtNlineFillRule, XtCLineFillRule, XtRInt, sizeof(int),
114      offset(lineFillRule), XtRImmediate, (XtPointer) FillSolid},
115     {XtNdownX, XtCDownX, XtRPosition, sizeof(Position),
116      offset(downX), XtRImmediate, (XtPointer) 0},
117     {XtNdownY, XtCDownY, XtRPosition, sizeof(Position),
118      offset(downY), XtRImmediate, (XtPointer) 0},
119     {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
120      offset(cursor), XtRString, (XtPointer) "watch"},
121     {XtNfilename, XtCfilename, XtRString, sizeof(String),
122      offset(filename), XtRString, (XtPointer) 0},
123     {XtNmenuwidgets, XtCmenuwidgets, XtRWidgetList, sizeof(WidgetList),
124      offset(menuwidgets), XtRWidgetList, (XtPointer) 0}
125 #undef offset
126 };
127 
128 /*
129 **  Some forward defines.
130  */
131 static void InitializeProc(Widget, Widget);
132 static void DestroyProc(Widget);
133 static void ResizeProc(Widget);
134 static void ExposeProc(Widget, XExposeEvent *);
135 static void RealizeProc(Widget, Mask *, XSetWindowAttributes *);
136 static Boolean SetValuesProc(Widget, Widget, Widget);
137 static void GetValuesHook(Widget, ArgList, Cardinal *);
138 static int QueryGeometryProc(Widget w, XtWidgetGeometry * proposed,
139 			     XtWidgetGeometry * reply);
140 
141 static XtGeometryResult
GeometryManager(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply)142 GeometryManager(Widget w, XtWidgetGeometry * request, XtWidgetGeometry * reply)
143 {
144     *reply = *request;
145 
146     if ((request->request_mode & CWX) != 0)
147 	w->core.x = request->x;
148     if ((request->request_mode & CWY) != 0)
149 	w->core.y = request->y;
150     if ((request->request_mode & CWWidth) != 0)
151 	w->core.width = request->width;
152     if ((request->request_mode & CWHeight) != 0)
153 	w->core.height = request->height;
154     if ((request->request_mode & CWBorderWidth) != 0)
155 	w->core.border_width = request->border_width;
156 
157     return XtGeometryYes;
158 }
159 
160 
161 PaintClassRec paintClassRec =
162 {
163     {				/* core fields */
164     /* superclass		*/ (WidgetClass) & compositeClassRec,
165     /* class_name		*/ "Paint",
166     /* widget_size		*/ sizeof(PaintRec),
167     /* class_initialize		*/ NULL,
168     /* class_part_initialize	*/ NULL,
169     /* class_inited		*/ FALSE,
170     /* initialize		*/ (XtInitProc) InitializeProc,
171     /* initialize_hook		*/ NULL,
172     /* realize			*/ RealizeProc,
173     /* actions			*/ NULL,
174     /* num_actions		*/ 0,
175     /* resources		*/ resources,
176     /* num_resources		*/ XtNumber(resources),
177     /* xrm_class		*/ NULLQUARK,
178     /* compress_motion		*/ FALSE,
179     /* compress_exposure	*/ TRUE,
180     /* compress_enterleave	*/ TRUE,
181     /* visible_interest		*/ FALSE,
182     /* destroy			*/ DestroyProc,
183     /* resize			*/ ResizeProc,
184     /* expose			*/ (XtExposeProc) ExposeProc,
185     /* set_values		*/ (XtSetValuesFunc) SetValuesProc,
186     /* set_values_hook		*/ NULL,
187     /* set_values_almost	*/ XtInheritSetValuesAlmost,
188     /* get_values_hook		*/ GetValuesHook,
189     /* accept_focus		*/ NULL,
190     /* version			*/ XtVersion,
191     /* callback_private		*/ NULL,
192     /* tm_table			*/ NULL,
193     /* query_geometry		*/ (XtGeometryHandler) QueryGeometryProc,
194     /* display_accelerator	*/ XtInheritDisplayAccelerator,
195     /* extension		*/ NULL
196     },
197     {				/* composite fields	    */
198     /* geometry_manager		*/ GeometryManager,
199     /* change_managed		*/ XtInheritChangeManaged,
200     /* insert_child		*/ XtInheritInsertChild,
201     /* delete_childion		*/ XtInheritDeleteChild,
202     /* extension		*/ NULL,
203     },
204     {				/* paint fields */
205 	0
206     }
207 };
208 
209 WidgetClass paintWidgetClass = (WidgetClass) & paintClassRec;
210 
211 Pixel
AlphaTwistPixel(Pixel p,unsigned char * u)212 AlphaTwistPixel(Pixel p, unsigned char *u)
213 {
214     unsigned char a;
215     unsigned short s;
216 
217     /* u[3] is alpha_mode */
218     if (u[3] == 2) {
219         a = u[0];
220         s = u[2] * (255-a);
221         get_color_components(p, u);
222         u[0] = (u[0] * a + s)>>8;
223         u[1] = (u[1] * a + s)>>8;
224         u[2] = (u[2] * a + s)>>8;
225     } else
226     if (u[3] == 3) {
227     	u[1] = u[2] = u[0];
228     } else {
229         /* mode == 1 */
230         a = u[0];
231         s = 255 - a;
232         get_color_components(p, u);
233         u[0] = (u[0] * a + Global.bg[0] * s)>>8;
234         u[1] = (u[1] * a + Global.bg[1] * s)>>8;
235         u[2] = (u[2] * a + Global.bg[2] * s)>>8;
236     }
237     return get_pixel_from_colors(u);
238 }
239 
240 Pixel
AlphaTwistPixel8(Pixel p,unsigned char * u)241 AlphaTwistPixel8(Pixel p, unsigned char *u)
242 {
243     unsigned char a;
244 
245     a = u[0]/23;
246     if (u[3] == 3) {
247 	if (u[1] >= a)
248             return Global.bg[4];
249 	else
250 	    return Global.bg[6];
251     } else
252     if (u[3] == 1) {
253 	if (u[1] >= a)
254 	    return Global.bg[6];
255         else
256 	    return p;
257     } else {
258 	if (u[1] >= a) {
259 	    if (u[2])
260 	        return Global.bg[6];
261 	    else
262 		return p;
263 	} else
264 	    return p;
265     }
266 }
267 
268 void
AlphaTwistImage(PaintWidget pw,XImage * xim,unsigned char * alpha,int width,int dx,int dy,int ax,int ay)269 AlphaTwistImage(PaintWidget pw, XImage *xim,
270                 unsigned char *alpha, int width,
271                 int dx, int dy, int ax, int ay)
272 {
273     int x, y;
274     Pixel p = 0;
275     unsigned char u[4];
276     PaintWidget pp = (pw->paint.paint)? (PaintWidget)pw->paint.paint : pw;
277 
278     u[3] = (unsigned char) pp->paint.alpha_mode;
279 
280     if (Global.depth <= 8) {
281         u[2] = 0;
282         for (y=0; y<xim->height; y++) {
283 	    for (x=0; x<xim->width; x++) {
284                 u[0] = alpha[dx+x+(dy+y)*width];
285                 u[1] = (unsigned char)((71*x+29*y)%12);
286                 if (u[3] <= 2) {
287                     p = xxGetPixel(xim, x, y);
288                     if (u[3] == 2) u[2] = ((ax+x)/12+(ay+y)/12)&1;
289 		}
290                 xxPutPixel(xim, x, y, AlphaTwistPixel8(p, u));
291 	    }
292 	}
293     } else {
294         for (y=0; y<xim->height; y++) {
295 	    for (x=0; x<xim->width; x++) {
296 	        u[0] = alpha[dx+x+(dy+y)*width];
297                 if (u[3] <= 2) {
298                     p = xxGetPixel(xim, x, y);
299                     if (u[3] == 2) u[2] = ALPHA_PIXEL_MODE(ax+x,ay+y);
300 	        }
301 	        xxPutPixel(xim, x, y, AlphaTwistPixel(p, u));
302 	    }
303 	}
304     }
305 }
306 
307 /*
308  * Attach a new undo buffer to the head of the undo list for this widget.
309  */
310 static UndoStack *
undoBuffer(PaintWidget w)311 undoBuffer(PaintWidget w)
312 {
313     UndoStack *new = (UndoStack *) xmalloc(sizeof(UndoStack));
314 
315     if (new == NULL)
316 	return NULL;
317 
318     new->box.x = 0;
319     new->box.y = 0;
320     new->box.width = 0;
321     new->box.height = 0;
322     new->alphapix.pixmap = None;
323     new->alphapix.alpha = NULL;
324     new->next = w->paint.head;
325     new->pushed = False;
326     w->paint.head = new;
327 
328     return new;
329 }
330 
331 static void
InitializeProc(Widget w,Widget newArg)332 InitializeProc(Widget w, Widget newArg)
333 {
334     PaintWidget new = (PaintWidget) newArg;
335     int i;
336     int zoom = new->paint.zoom;
337     UndoStack * cur;
338 
339     if (zoom == PwZoomParent && new->paint.paint == None)
340 	zoom = new->paint.zoom = 1;
341 
342     if (zoom == PwZoomParent)
343 	zoom = 1;
344     else if (zoom == -1)
345 	zoom = new->paint.zoom = 1;
346 
347     if (new->paint.sourcePixmap != None) {
348 	Window root;
349 	int x, y;
350 	unsigned int width, height, bw, depth;
351 
352 	XGetGeometry(XtDisplay(w), new->paint.sourcePixmap,
353 		     &root, &x, &y, &width, &height, &bw, &depth);
354 
355 	new->paint.drawWidth = width;
356 	new->paint.drawHeight = height;
357     } else if (new->paint.paint != None) {
358 	PaintWidget parent = (PaintWidget) new->paint.paint;
359 
360 	new->paint.drawWidth = parent->paint.drawWidth;
361 	new->paint.drawHeight = parent->paint.drawHeight;
362     }
363     if (new->core.width == 0) {
364         if (zoom>0)
365 	    new->core.width = new->paint.drawWidth * zoom;
366         else
367 	    new->core.width = (new->paint.drawWidth-zoom-1)/(-zoom);
368     }
369     if (new->core.height == 0) {
370         if (zoom>0)
371 	    new->core.height = new->paint.drawHeight * zoom;
372         else
373 	    new->core.height = (new->paint.drawHeight-zoom-1)/(-zoom);
374     }
375 
376     new->paint.foreground = BlackPixelOfScreen(XtScreen(new));
377     new->paint.background = WhitePixelOfScreen(XtScreen(new));
378 
379     new->paint.gc = None;
380     new->paint.igc = None;
381     new->paint.sgc = None;
382     new->paint.fgc = None;
383     new->paint.mgc = None;
384     new->paint.xgc = None;
385     new->paint.tgc = None;
386 
387     /*
388     **	Init the undo stuff
389      */
390     new->paint.head = NULL;
391     if (new->paint.paint == None) {
392 	cur = undoBuffer(new);
393 	for (i = 0; i <= new->paint.undoSize; i++)
394 	    undoBuffer(new);
395 	cur->next = new->paint.head;
396 	UndoInitialize(new, new->paint.undoSize);
397 	new->paint.undo = new->paint.head;
398 	new->paint.current = new->paint.head->alphapix;
399     } else {
400 	new->paint.undo = NULL;
401 	new->paint.current.pixmap = None;
402 	new->paint.current.alpha = NULL;
403     }
404 
405     /*
406     **	The region information
407      */
408     new->paint.region.isVisible = False;
409     new->paint.region.mask = None;
410     new->paint.region.source = None;
411     new->paint.region.notMask = None;
412     new->paint.region.fg_gc = None;
413     new->paint.region.bg_gc = None;
414     new->paint.region.child = None;
415     new->paint.region.sourceImg = NULL;
416     new->paint.region.maskImg = NULL;
417     new->paint.region.notMaskImg = NULL;
418     new->paint.region.alpha = NULL;
419     new->paint.region.proc = NULL;
420 
421     for (i = 0; i < XtNumber(new->paint.region.grip); i++)
422 	new->paint.region.grip[i] = None;
423 
424     /*
425     **	Now the backing store image
426      */
427     new->paint.image = NULL;
428 
429     /*
430     **
431      */
432     new->paint.paintChildrenSize = 0;
433     new->paint.paintChildren = NULL;
434     new->paint.filename = NULL;
435     new->paint.menuwidgets = NULL;
436 }
437 
438 static XRectangle *
GetRectangle(PaintWidget w)439 GetRectangle(PaintWidget w)
440 {
441     static XRectangle rect;
442     XRectangle *rp = &rect, newRect;
443     Widget cur;
444     Widget prev = (Widget) w;
445     int dx, dy;
446 
447     rect.x = dx = 0;
448     rect.y = dy = 0;
449     rect.width = w->core.width;
450     rect.height = w->core.height;
451 
452     /*
453     **	Climb the tree to find the visible area.
454     **
455      */
456     for (cur = XtParent((Widget) w); !XtIsShell(cur); cur = XtParent(cur)) {
457 	dx += -prev->core.x;
458 	dy += -prev->core.y;
459 	newRect.x = dx;
460 	newRect.y = dy;
461 	newRect.width = cur->core.width;
462 	newRect.height = cur->core.height;
463 
464 	rp = RectIntersect(&newRect, rp);
465 
466 	prev = cur;
467     }
468 
469     if (rp != NULL)
470 	rect = *rp;
471     else
472 	rect.x = rect.y = rect.width = rect.height = 0;
473 
474     return &rect;
475 }
476 
477 static void
RealizeProc(Widget w,Mask * valueMask,XSetWindowAttributes * attributes)478 RealizeProc(Widget w, Mask * valueMask,
479 	    XSetWindowAttributes * attributes)
480 {
481     XWindowAttributes wattr;
482     PaintWidget pw = (PaintWidget) w;
483     PaintWidget pp = (PaintWidget) pw->paint.paint;
484     UndoStack *cur;
485     Window root;
486     int x, y, i;
487     unsigned int width, height, bw, depth;
488     XGCValues values;
489 
490     XtCreateWindow(w, InputOutput, CopyFromParent, *valueMask, attributes);
491 
492     XGetGeometry(XtDisplay(w), XtWindow(w),
493 		 &root, &x, &y, &width, &height, &bw, &depth);
494 
495     values.foreground = pw->paint.foreground;
496     values.background = pw->core.background_pixel;
497     pw->paint.gc = XtGetGC(w, GCForeground | GCBackground, &values);
498 
499     if (pp == None) {
500 	/*
501 	**  Inverse of the base colors.
502 	 */
503 	values.foreground = pw->core.background_pixel;
504 	values.background = pw->paint.foreground;
505 	pw->paint.igc = XCreateGC(XtDisplay(w), XtWindow(w),
506 				  GCForeground | GCBackground, &values);
507 	pw->paint.tgc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
508 
509 	values.function = GXxor;
510 	values.foreground = ~0;
511 	values.subwindow_mode = IncludeInferiors;
512 	pw->paint.xgc = XCreateGC(XtDisplay(w), XtWindow(w),
513 		   GCForeground | GCFunction | GCSubwindowMode, &values);
514     } else {
515 	pw->paint.igc = pp->paint.igc;
516 	pw->paint.tgc = pp->paint.tgc;
517 	pw->paint.xgc = pp->paint.xgc;
518 
519 	pw->paint.lineWidth = pp->paint.lineWidth;
520     }
521 
522     /*
523     **	Create the filled gc information
524      */
525     if (pw->paint.paint == None) {
526 	pw->paint.sgc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
527 	pw->paint.fgc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
528 	XSetForeground(XtDisplay(w), pw->paint.fgc, pw->paint.foreground);
529 	XSetForeground(XtDisplay(w), pw->paint.sgc, pw->paint.lineForeground);
530 
531 	/*
532 	**  First the fill GC
533 	 */
534 	XSetFillStyle(XtDisplay(w), pw->paint.fgc, pw->paint.fillRule);
535 	XSetLineAttributes(XtDisplay(w), pw->paint.fgc,
536 			   pw->paint.lineWidth, LineSolid,
537 			   CapRound, Global.join);
538 	if (pw->paint.pattern != None)
539 	    XSetTile(XtDisplay(w), pw->paint.fgc, pw->paint.pattern);
540 
541 	/*
542 	**  Then the line GC
543 	 */
544 	XSetFillStyle(XtDisplay(w), pw->paint.sgc, pw->paint.lineFillRule);
545 	XSetLineAttributes(XtDisplay(w), pw->paint.sgc,
546 			   pw->paint.lineWidth, LineSolid,
547 			   CapRound, Global.join);
548 	if (pw->paint.linePattern != None)
549 	    XSetTile(XtDisplay(w), pw->paint.sgc, pw->paint.linePattern);
550     } else if (pw->paint.paint != None) {
551 	pw->paint.sgc = pp->paint.sgc;
552 	pw->paint.fgc = pp->paint.fgc;
553     }
554     /*
555     **	Parent realized after children, odd..
556      */
557     if (pp == None && pw->paint.paintChildrenSize != 0)
558 	for (i = 0; i < pw->paint.paintChildrenSize; i++) {
559 	    PaintWidget tp = (PaintWidget) pw->paint.paintChildren[i];
560 	    tp->paint.sgc = pw->paint.sgc;
561 	    tp->paint.fgc = pw->paint.fgc;
562 	    tp->paint.igc = pw->paint.igc;
563 	    tp->paint.xgc = pw->paint.xgc;
564 	    tp->paint.tgc = pw->paint.tgc;
565 	}
566     /*
567     **	Create the backing undo buffers
568      */
569     for (cur = pw->paint.head; cur && (cur->alphapix.pixmap == None);
570          cur = cur->next) {
571 	cur->alphapix.pixmap = XCreatePixmap(XtDisplay(w), XtWindow(w),
572 			       pw->paint.drawWidth, pw->paint.drawHeight,
573 				    depth);
574         cur->alphapix.alpha = NULL;
575     }
576 
577     /*
578     **	If this paint widget is the child of another paint
579     **	 widget then either create our own unique information
580     **	 or just use the information from our parent.
581      */
582     if (pw->paint.paint == None) {
583 	pw->paint.current = pw->paint.head->alphapix;
584 
585 	if (pw->paint.sourcePixmap != None)
586 	    pwSetPixmap(pw, pw->paint.sourcePixmap, FALSE);
587 	else
588 	    XFillRectangle(XtDisplay(w), pw->paint.current.pixmap,
589 			   pw->paint.igc, 0, 0,
590 			   pw->paint.drawWidth, pw->paint.drawHeight);
591     } else
592 	PwAddChild(pw->paint.paint, w);
593 
594     XGetWindowAttributes(XtDisplay(w), XtWindow(w), &wattr);
595     pw->paint.visual = wattr.visual;
596 
597     if (pw->paint.cursor != None)
598 	XDefineCursor(XtDisplay(pw), XtWindow(pw), pw->paint.cursor);
599 }
600 
601 static void
DestroyProc(Widget w)602 DestroyProc(Widget w)
603 {
604     PaintWidget pw = (PaintWidget) w;
605     UndoStack *cur, *nxt;
606 
607     if (pw->paint.mgc != None)
608 	XFreeGC(XtDisplay(pw), pw->paint.mgc);
609     if (pw->paint.gc != None)
610 	XtReleaseGC(w, pw->paint.gc);
611 
612     if (pw->paint.region.source != None)
613 	XFreePixmap(XtDisplay(pw), pw->paint.region.source);
614     if (pw->paint.region.mask != None)
615 	XFreePixmap(XtDisplay(pw), pw->paint.region.mask);
616     if (pw->paint.region.notMask != None)
617 	XFreePixmap(XtDisplay(pw), pw->paint.region.notMask);
618     if (pw->paint.region.sourceImg != NULL)
619 	XDestroyImage(pw->paint.region.sourceImg);
620     if (pw->paint.region.maskImg != NULL)
621 	XDestroyImage(pw->paint.region.maskImg);
622     if (pw->paint.region.notMaskImg != NULL)
623 	XDestroyImage(pw->paint.region.notMaskImg);
624 
625     if (pw->paint.paint != None)
626 	return;
627 
628     /*	WARNING: the rest of this callback doesn't execute for children */
629 
630     if (pw->paint.filename != NULL)
631 	free(pw->paint.filename);
632     if (pw->paint.menuwidgets != NULL)
633 	free(pw->paint.menuwidgets);
634 
635     if (pw->paint.tgc != None)
636 	XFreeGC(XtDisplay(pw), pw->paint.tgc);
637     if (pw->paint.xgc != None)
638 	XFreeGC(XtDisplay(pw), pw->paint.xgc);
639     if (pw->paint.igc != None)
640 	XFreeGC(XtDisplay(pw), pw->paint.igc);
641     if (pw->paint.fgc != None)
642 	XFreeGC(XtDisplay(pw), pw->paint.fgc);
643     if (pw->paint.sgc != None)
644 	XFreeGC(XtDisplay(pw), pw->paint.sgc);
645 
646     cur = pw->paint.head;
647     do {
648 	nxt = cur->next;
649 	if (cur->alphapix.pixmap != None) {
650 	    XFreePixmap(XtDisplay(pw), cur->alphapix.pixmap);
651             cur->alphapix.pixmap = None;
652 	}
653 	if (cur->alphapix.alpha != NULL) {
654 	    XtFree((char *)cur->alphapix.alpha);
655             cur->alphapix.alpha = NULL;
656 	}
657 	XtFree((XtPointer) cur);
658 	cur = nxt;
659     }
660     while (cur != pw->paint.head);
661 
662     if (pw->paint.image != NULL) {
663 	XDestroyRegion(pw->paint.imageRegion);
664 	XDestroyImage(pw->paint.image);
665     }
666     if (pw->paint.paintChildren != NULL)
667 	XtFree((XtPointer) pw->paint.paintChildren);
668 }
669 
670 static void
ResizeProc(Widget w)671 ResizeProc(Widget w)
672 {
673 }
674 
675 /*
676 **  Update the zoomed region as specified by rect.
677 **    rect is in screen coordinates.
678 **
679 **  There are two drawers, the first draws using rectangles
680 **   the second draws using XImages.
681 **
682  */
683 
684 #ifdef ZOOM_DRAW_RECTS
685 static void
ZoomDrawRects(PaintWidget pw,Widget w,GC gc,XImage * xim,XImage * mask,Boolean isExpose,int xstart,int ystart,int zoom,XRectangle * rect)686 ZoomDrawRects(PaintWidget pw, Widget w, GC gc, XImage * xim, XImage * mask,
687 	      Boolean isExpose, int xstart, int ystart, int zoom,
688 	      XRectangle * rect)
689 {
690     static Boolean *flags = NULL;
691     static int flagsSize = 0;
692     Display *dpy = XtDisplay(w);
693     Window win = XtWindow(w);
694     int width = rect->width;
695     int count = (rect->width+1) * (rect->height+1);
696     XRectangle rects[256];
697     int index, i, n;
698     unsigned char *alpha = pw->paint.current.alpha;
699     unsigned char a, ap, u[4];
700     Pixel p, pp, q;
701 
702     if (flagsSize < count) {
703 	int allocSize = (count + 4) * sizeof(Boolean);
704 	if (flags == NULL)
705 	    flags = (Boolean *) xmalloc(allocSize);
706 	else
707 	    flags = (Boolean *) XtRealloc((XtPointer) flags, allocSize);
708 	flagsSize = count;
709     }
710     memset(flags, 0, flagsSize * sizeof(Boolean));
711 
712     if (mask != NULL) {
713 	int x, y;
714 
715 	i = 0;
716 	for (y = rect->y; y < rect->height + rect->y; y++) {
717 	    for (x = rect->x; x < rect->width + rect->x; x++, i++) {
718 		if (!XGetPixel(mask, x, y))
719 		    flags[i] = True;
720 	    }
721 	}
722     }
723 
724     n = XtNumber(rects);
725     if (alpha) {
726         u[3] = (unsigned char) pw->paint.alpha_mode;
727         if (u[3] == 2) n = 1;
728     } else
729         u[3] = 0;
730 
731     for (i = 0; i < n && i < count; i++)
732 	if (zoom > ZOOM_THRESH)
733 	    rects[i].width = rects[i].height = zoom - 1;
734 	else
735 	    rects[i].width = rects[i].height = zoom;
736 
737     for (index = 0; index != count; index++) {
738 	if (!flags[index]) {
739 	    int xindex = index % width + rect->x;
740 	    int yindex = index / width + rect->y;
741 	    int xindexEnd = rect->x + rect->width;
742 	    int xpos = (index % width + xstart) * zoom;
743 	    int ypos = (index / width + ystart) * zoom;
744 	    int pos, flag;
745 
746             p = xxGetPixel(xim, xindex, yindex);
747             if (u[3]) {
748 	        a = alpha[xindex + yindex*pw->paint.drawWidth];
749                 u[0] = a;
750 	        if (u[3] == 2) u[2] = ALPHA_PIXEL_MODE(xindex, yindex);
751                 q = AlphaTwistPixel(p, u);
752 	    } else
753 	        q = p;
754 
755 	    flag = (isExpose && p == w->core.background_pixel);
756 
757 	    XSetForeground(dpy, gc, q);
758 	    for (pos = index, i = 0; pos != count;
759 		 pos++, xindex++, xpos += zoom) {
760 		if (xindex == xindexEnd) {
761 		    xindex = rect->x;
762 		    xpos = xstart * zoom;
763 		    yindex++;
764 		    ypos += zoom;
765 		}
766                 pp = xxGetPixel(xim, xindex, yindex);
767                 if (u[3])
768 	            ap = alpha[xindex + yindex*pw->paint.drawWidth];
769 
770 		if (flags[pos] || pp != p || ap != a)
771 		    continue;
772 
773 		flags[pos] = True;
774 
775 		if (flag)
776 		    continue;
777 
778 		rects[i].x = xpos;
779 		rects[i].y = ypos;
780 		i++;
781 
782                 if (u[3] == 2) {
783 		    u[0] = a;
784 		    u[2] = ALPHA_PIXEL_MODE(xindex, yindex);
785                     q = AlphaTwistPixel(p, u);
786 	            XSetForeground(dpy, gc, q);
787 	        }
788 
789 		if (i == n) {
790 		    XFillRectangles(dpy, win, gc, rects, i);
791 		    i = 0;
792 		}
793 	    }
794 	    if (i > 0)
795 		XFillRectangles(dpy, win, gc, rects, i);
796 	}
797     }
798 }
799 #endif
800 
801 extern int alpha_special_mode;
802 
803 static void
ZoomDrawImage(PaintWidget pw,Widget w,GC gc,XImage * xim,XImage * mask,Boolean isExpose,int xstart,int ystart,int zoom,XRectangle * rect)804 ZoomDrawImage(PaintWidget pw, Widget w, GC gc, XImage * xim, XImage * mask,
805 	      Boolean isExpose, int xstart, int ystart, int zoom,
806 	      XRectangle * rect)
807 {
808     Display *dpy = XtDisplay(w);
809     int width = rect->width;
810     int height = rect->height;
811     int widthp, heightp;
812     Pixmap pix;
813     XImage *dst;
814     XImage *dstMask = NULL;
815     Pixel p = 0;
816     int bytes_per_pixel, zoom_bytes_per_pixel;
817     int k, l, m, x, y, x1, y1, x2, y2, dx, dy, rx, ry, sx, sy;
818     int numDraw;
819     int endX;
820     int endY;
821     int interpolation;
822     unsigned char u[4];
823     unsigned int s[3];
824     unsigned char *alpha;
825     PaintWidget pp = (pw->paint.paint)? (PaintWidget)pw->paint.paint : pw;
826 
827     alpha = pp->paint.current.alpha;
828     if (alpha)
829         u[3] =  (unsigned char)pp->paint.alpha_mode;
830     else
831         u[3] = 0;
832     if (alpha_special_mode) {
833         if (pp->paint.region.undo_alphapix.alpha)
834 	  alpha = pp->paint.region.undo_alphapix.alpha;
835         rx = 0;
836         ry = 0;
837         sx = rect->x;
838         sy = rect->y;
839     } else {
840         rx = rect->x;
841         ry = rect->y;
842         sx = 0;
843         sy = 0;
844     }
845 
846     if (zoom<0) {
847         zoom = -zoom;
848         XtVaGetValues((Widget)pp, XtNinterpolation, &interpolation, NULL);
849         if (Global.depth<=8) interpolation = 0;
850         widthp = (width+zoom-1)/zoom;
851         heightp = (height+zoom-1)/zoom;
852         dst = XCreateImage(dpy, pp->paint.visual, xim->depth, xim->format,
853 		           0, NULL, widthp, heightp, 32, 0);
854         dst->data = (char *) xmalloc(heightp * dst->bytes_per_line);
855 
856         if (mask) {
857             dstMask = XCreateImage(dpy, pp->paint.visual,
858 			           mask->depth, mask->format,
859 			           0, NULL, widthp, heightp, 8, 0);
860 	    dstMask->data = (char *)
861                      xmalloc(heightp * dstMask->bytes_per_line);
862 	    memset(dstMask->data, 0, heightp * dstMask->bytes_per_line);
863 	}
864 
865 	bytes_per_pixel = xim->bits_per_pixel >> 3;
866         zoom_bytes_per_pixel = zoom*bytes_per_pixel;
867 	if (!interpolation || xim->bits_per_pixel != 8*bytes_per_pixel) {
868         /* fallback procedure */
869 	    for (y = 0; y < heightp; y++) {
870 	        dy = y*zoom ;
871 	        for (x = 0; x < widthp; x++) {
872 	            dx = x*zoom;
873                     if (mask) {
874                         if (!XGetPixel(mask, dx+rx, dy+ry)) continue;
875 		        XPutPixel(dstMask, x, y, True);
876 		    }
877                     if (u[3]) {
878                         u[0] = alpha[dx+sx+(sy+dy)*pp->paint.drawWidth];
879                         if (u[3] <= 2) {
880                             p = xxGetPixel(xim, dx+rx, dy+ry);
881                             if (u[3] == 2)
882                                 u[2] = ALPHA_PIXEL_MODE(dx+sx, sy+dy);
883 			}
884                         p = AlphaTwistPixel(p, u);
885 		    } else
886 		        p = xxGetPixel(xim, dx+rx, dy+ry);
887 		    xxPutPixel(dst, x, y, p);
888 		}
889 	    }
890 	} else {
891         /* regular procedure */
892 	    for (y = 0; y < heightp; y++) {
893 	        dy = y*zoom;
894 	        y1 = dy + ry;
895                 y2 = y1 + zoom;
896                 if (y2 > (k=ry + height)) y2 = k;
897 	        for (x = 0; x < widthp; x++) {
898 		    dx = x*zoom;
899                     if (mask) {
900                         if (!XGetPixel(mask, dx+rx, dy+ry)) continue;
901 		        XPutPixel(dstMask, x, y, True);
902 		    }
903                     x1 = dx + rx;
904                     x2 = x1 + zoom;
905                     if (x2 > (k=rx + width)) x2 = k;
906                     for (k=0; k<=2; k++) s[k] = 0;
907   		    for (m=y1; m<y2; m++) {
908 		        for (l=x1; l<x2; l++) {
909                             if (u[3]) {
910 			        u[0] = alpha[(l+sx)+(m+sy)*pp->paint.drawWidth];
911 			        if (u[3] <= 2) {
912 			            p = xxGetPixel(xim, l, m);
913                                     if (u[3] == 2)
914                                         u[2] = ALPHA_PIXEL_MODE(l+sx, m+sy);
915 				}
916                                 p = AlphaTwistPixel(p, u);
917 			    } else {
918 			        p = xxGetPixel(xim, l, m);
919                                 get_color_components(p, u);
920 			    }
921                             for (k=0; k<=2; k++)
922                                 s[k] += (unsigned int)u[k];
923 			}
924 		    }
925                     l = (x2-x1)*(y2-y1);
926                     for (k=0; k<=2; k++)
927 			u[k] = (unsigned char)(s[k]/(unsigned int)l);
928                     p = get_pixel_from_colors(u);
929                     xxPutPixel(dst, x, y, p);
930 		}
931 	    }
932 	}
933         if (mask) {
934 	    pix = XCreatePixmap(dpy, XtWindow(w),
935 				widthp, heightp, 1);
936   	    XPutImage(dpy, pix, pw->paint.mgc, dstMask,
937 		      0, 0, 0, 0, widthp, heightp);
938 	    XSetClipOrigin(dpy, gc, xstart/zoom, ystart/zoom);
939 	    XSetClipMask(dpy, gc, pix);
940 	    XPutImage(dpy, XtWindow(w), gc, dst, 0, 0,
941 		      xstart/zoom, ystart/zoom,
942 		      widthp, heightp);
943             XSetClipMask(dpy, gc, None);
944 	    XFreePixmap(dpy, pix);
945 	} else
946             XPutImage(dpy, XtWindow(w), gc, dst, 0, 0,
947 	              xstart/zoom, ystart/zoom,
948 		      widthp, heightp);
949         goto end;
950     }
951 
952     numDraw = zoom - ((zoom > ZOOM_THRESH) ? 1 : 0);
953     endX = rx + rect->width;
954     endY = ry + rect->height;
955 
956     dst = XCreateImage(dpy, pp->paint.visual, xim->depth, xim->format,
957   	               0, NULL, width * zoom, height * zoom, 32, 0);
958     dst->data = (char *) xmalloc(height * zoom * dst->bytes_per_line);
959 
960     if (mask) {
961         dstMask = XCreateImage(dpy, pp->paint.visual,
962 			       mask->depth, mask->format,
963 			       0, NULL, width * zoom, height * zoom, 8, 0);
964 	dstMask->data = (char *)
965                      xmalloc(height * zoom * dstMask->bytes_per_line);
966 	memset(dstMask->data, 0, height * zoom * dstMask->bytes_per_line);
967     }
968 
969     for (dy = 0, y = ry; y < endY; y++, dy += zoom) {
970 	for (dx = 0, x = rx; x < endX; x++, dx += zoom) {
971 	    if (mask && !XGetPixel(mask, x, y))
972              	continue;
973             if (u[3]) {
974 	        u[0] = alpha[x+sx+(y+sy)*pw->paint.drawWidth];
975                 if (u[3] <= 2) {
976 		    p = xxGetPixel(xim, x, y);
977 		    if (u[3] == 2)
978                         u[2] = ALPHA_PIXEL_MODE(x+sx, y+sy);
979 		}
980                 p = AlphaTwistPixel(p, u);
981 	    } else
982 	        p = xxGetPixel(xim, x, y);
983 	    for (y1 = 0; y1 < numDraw; y1++) {
984 		for (x1 = 0; x1 < numDraw; x1++) {
985 		    xxPutPixel(dst, dx + x1, dy + y1, p);
986 		    if (mask) XPutPixel(dstMask, dx + x1, dy + y1, True);
987 		}
988 		if (numDraw != zoom)
989 		    xxPutPixel(dst, dx + x1, dy + y1,
990 			       w->core.background_pixel);
991 	    }
992 	    if (numDraw != zoom)
993 		for (x1 = 0; x1 < zoom; x1++)
994 		    xxPutPixel(dst, dx + x1, dy + y1,
995 			       w->core.background_pixel);
996 	}
997     }
998 
999     if (mask) {
1000         pix = XCreatePixmap(XtDisplay(w), XtWindow(w),
1001 			    width * zoom, height * zoom, 1);
1002 	XPutImage(XtDisplay(w), pix, pw->paint.mgc, dstMask,
1003 		  0, 0, 0, 0, width * zoom, height * zoom);
1004 	XSetClipOrigin(XtDisplay(w), gc, xstart * zoom, ystart * zoom);
1005 	XSetClipMask(XtDisplay(w), gc, pix);
1006 	XPutImage(XtDisplay(w), XtWindow(w), gc, dst, 0, 0,
1007 		  xstart * zoom, ystart * zoom,
1008 		  width * zoom, height * zoom);
1009 	XSync(XtDisplay(w), False);
1010 	XSetClipMask(XtDisplay(w), gc, None);
1011 	XFreePixmap(XtDisplay(w), pix);
1012     } else
1013 	XPutImage(XtDisplay(w), XtWindow(w), gc, dst, 0, 0,
1014 		  xstart * zoom, ystart * zoom,
1015 		  width * zoom, height * zoom);
1016 
1017  end:
1018     XSync(XtDisplay(w), False);
1019     XDestroyImage(dst);
1020     if (dstMask != NULL)
1021 	XDestroyImage(dstMask);
1022 }
1023 
1024 void
zoomUpdate(PaintWidget pw,Boolean isExpose,XRectangle * rect)1025 zoomUpdate(PaintWidget pw, Boolean isExpose, XRectangle * rect)
1026 {
1027     int zoom = GET_ZOOM(pw);
1028     int sx, sy, w, h, zsx, zsy;
1029     XRectangle *isec, *tmp;
1030     XRectangle real, grab;
1031     XImage *xim;
1032 
1033     if ((isec = RectIntersect(rect, GetRectangle(pw))) == NULL)
1034         return;
1035 
1036     if (zoom>0) {
1037         zsx = sx = isec->x / zoom;
1038         zsy = sy = isec->y / zoom;
1039         w = (isec->width + (isec->x % zoom) + zoom - 1) / zoom;
1040         h = (isec->height + (isec->y % zoom) + zoom - 1) / zoom;
1041     } else {
1042         zsx = sx = isec->x * (-zoom);
1043         zsy = sy = isec->y * (-zoom);
1044         w = isec->width * (-zoom);
1045         h = isec->height * (-zoom);
1046     }
1047 
1048     grab.x = sx + pw->paint.zoomX;
1049     grab.y = sy + pw->paint.zoomY;
1050     grab.width = w;
1051     grab.height = h;
1052     real.x = 0;
1053     real.y = 0;
1054     real.width = pw->paint.drawWidth;
1055     real.height = pw->paint.drawHeight;
1056 
1057     if ((tmp = RectIntersect(&grab, &real)) == NULL)
1058 	return;
1059 
1060     xim = PwGetImage((Widget) pw, tmp);
1061 
1062     real.x = tmp->x;
1063     real.y = tmp->y;
1064     real.width = tmp->width;
1065     real.height = tmp->height;
1066 
1067     PwZoomDraw(pw, (Widget) pw, pw->paint.tgc, xim, NULL,
1068 	       isExpose, sx, sy, zoom, &real);
1069 }
1070 
1071 /*
1072 **  pw	= parent paint widget
1073 **  w	= widget whose window will be updated
1074 **  gc	= gc to use (read/written)
1075 **  src = source XImage to use
1076 **  mask = mask XImage to use
1077 **  flag = is this an expose event, so we don't have to
1078 **	   update pixels == window background
1079 **  sx,sy = start x, y for window drawing (non-zoomed)
1080 **  zoom = zoom value to apply
1081 **  rect = region of the input ximages to use to draw
1082 **	   a start x,y with the specified width,height
1083  */
1084 void
PwZoomDraw(PaintWidget pw,Widget w,GC gc,XImage * src,XImage * mask,Boolean flag,int sx,int sy,int zoom,XRectangle * rect)1085 PwZoomDraw(PaintWidget pw, Widget w, GC gc, XImage * src, XImage * mask,
1086 	    Boolean flag, int sx, int sy, int zoom, XRectangle * rect)
1087 {
1088 #ifdef ZOOM_DRAW_RECTS
1089     PaintWidget pp = (pw->paint.paint)? (PaintWidget) pw->paint.paint : pw;
1090     if (0 && zoom>0 && pp == pw &&
1091         rect->width * rect->height < 1024 + 256)
1092 	ZoomDrawRects(pw, w, gc, src, mask, flag, sx, sy, zoom, rect);
1093     else
1094 #endif
1095     ZoomDrawImage(pw, w, gc, src, mask, flag, sx, sy, zoom, rect);
1096 
1097     if (pw->paint.grid)
1098 	PwDrawVisibleGrid(pw, w, True, sx, sy,
1099                           sx + rect->width, sy + rect->height);
1100 }
1101 
1102 void
PwUpdateDrawable(Widget w,Drawable draw,XRectangle * rect)1103 PwUpdateDrawable(Widget w, Drawable draw, XRectangle * rect)
1104 {
1105     PaintWidget pw = (PaintWidget) w;
1106     PaintWidget pp = (pw->paint.paint)? (PaintWidget)pw->paint.paint : pw;
1107     XRectangle all;
1108     Pixmap pix = GET_PIXMAP(pw);
1109     XImage *xim;
1110 
1111     if (rect == NULL || rect->width == 0 || rect->height == 0) {
1112 	rect = &all;
1113 	all.x = all.y = 0;
1114 	all.width = pw->core.width;
1115 	all.height = pw->core.height;
1116     }
1117 
1118     if (pp->paint.current.alpha && pp->paint.alpha_mode!=0 &&
1119         draw == XtWindow(w)) {
1120         xim = XGetImage(XtDisplay(w), pix,
1121                         rect->x + pw->paint.zoomX,
1122                         rect->y + pw->paint.zoomY,
1123                         rect->width, rect->height,
1124                         AllPlanes, ZPixmap);
1125         AlphaTwistImage(pw, xim, pp->paint.current.alpha,
1126                         pw->paint.drawWidth,
1127                         rect->x + pw->paint.zoomX,
1128                         rect->y + pw->paint.zoomY,
1129                         rect->x + pw->paint.zoomX,
1130                         rect->y + pw->paint.zoomY);
1131         XPutImage(XtDisplay(w), draw, pw->paint.gc,
1132 	          xim, 0, 0, rect->x, rect->y,
1133 	          rect->width, rect->height);
1134         XDestroyImage(xim);
1135     } else {
1136         XCopyArea(XtDisplay(w), pix, draw, pw->paint.gc,
1137 	          rect->x + pw->paint.zoomX,
1138 	          rect->y + pw->paint.zoomY,
1139 	          rect->width, rect->height,
1140 	          rect->x, rect->y);
1141     }
1142 }
1143 
1144 static void
realExposeProc(PaintWidget pw,XExposeEvent * event,Boolean flag)1145 realExposeProc(PaintWidget pw, XExposeEvent * event, Boolean flag)
1146 {
1147     int x, y, width, height, zoom;
1148     XRectangle rect;
1149 
1150     if (!XtIsRealized(((Widget) pw)))
1151 	return;
1152 
1153     /*
1154     **	Clean up the event, since I do simulate them
1155      */
1156     x = event->x;
1157     y = event->y;
1158     width = event->width;
1159     height = event->height;
1160 
1161     if (x < 0) {
1162 	width += x;
1163 	x = 0;
1164     }
1165     if (y < 0) {
1166 	height += y;
1167 	y = 0;
1168     }
1169     if (width < 0 || height < 0)
1170 	return;
1171     if (x > pw->core.width || y > pw->core.height)
1172 	return;
1173     if (x + width > pw->core.width)
1174 	width = pw->core.width - x;
1175     if (y + height > pw->core.height)
1176 	height = pw->core.height - y;
1177 
1178     zoom = GET_ZOOM(pw);
1179 
1180     rect.x = x;
1181     rect.y = y;
1182     rect.width = width+(zoom<0);
1183     rect.height = height+(zoom<0);
1184 
1185     if (zoom == 1) {
1186 	PwUpdateDrawable((Widget) pw, XtWindow((Widget) pw), &rect);
1187         if (pw->paint.grid)
1188 	    PwDrawVisibleGrid(pw, (Widget)pw, True, x, y,
1189                               x + rect.width, y + rect.height);
1190     } else
1191 	zoomUpdate(pw, flag, &rect);
1192 
1193     XSync(XtDisplay(pw), False);
1194 }
1195 
1196 static void
ExposeProc(Widget w,XExposeEvent * event)1197 ExposeProc(Widget w, XExposeEvent * event)
1198 {
1199     realExposeProc((PaintWidget) w, event, True);
1200 }
1201 
1202 static void
resizePixmap(PaintWidget w,AlphaPixmap * alphapix)1203 resizePixmap(PaintWidget w, AlphaPixmap * alphapix)
1204 {
1205     Pixmap n;
1206     unsigned char * alpha = NULL;
1207     int w1, h1, w2, h2, y;
1208 
1209     if (alphapix == NULL || alphapix->pixmap == None)
1210 	return;
1211 
1212     n = XCreatePixmap(XtDisplay(w), XtWindow(w),
1213 		      w->paint.drawWidth, w->paint.drawHeight,
1214 		      w->core.depth);
1215     XFillRectangle(XtDisplay(w), n,
1216 		   w->paint.igc, 0, 0,
1217 		   w->paint.drawWidth, w->paint.drawHeight);
1218     XCopyArea(XtDisplay(w), alphapix->pixmap, n,
1219 	      w->paint.gc, 0, 0,
1220 	      w->paint.drawWidth, w->paint.drawHeight, 0, 0);
1221 
1222     if (alphapix->alpha) {
1223         GetPixmapWHD(XtDisplay(w), alphapix->pixmap, &w1, &h1, &y);
1224         y = w->paint.drawWidth * w->paint.drawHeight;
1225         alpha = (unsigned char *) xmalloc(y);
1226         memset(alpha, (unsigned char)Global.alpha_bg, y);
1227         w2 = w1;
1228         if (w2>w->paint.drawWidth) w2 = w->paint.drawWidth;
1229         h2 = h1;
1230         if (h2>w->paint.drawHeight) h2 = w->paint.drawHeight;
1231         for (y=0; y<h2; y++)
1232 	    memcpy(alpha+y*w->paint.drawWidth, alphapix->alpha+y*w1, w2);
1233 	free(alphapix->alpha);
1234     }
1235 
1236     XFreePixmap(XtDisplay(w), alphapix->pixmap);
1237     alphapix->pixmap = n;
1238     alphapix->alpha = alpha;
1239 }
1240 
1241 static Boolean
SetValuesProc(Widget curArg,Widget request,Widget newArg)1242 SetValuesProc(Widget curArg, Widget request,
1243 	      Widget newArg)
1244 {
1245     PaintWidget cur = (PaintWidget) curArg;
1246     PaintWidget new = (PaintWidget) newArg;
1247     int ret = False;
1248     int sizeChanged = False;
1249     int i, zoom;
1250 
1251     if (cur->paint.sourcePixmap != new->paint.sourcePixmap)
1252 	pwSetPixmap(new, new->paint.sourcePixmap, True);
1253 
1254     if (cur->paint.compress != new->paint.compress)
1255 	new->core.widget_class->core_class.compress_motion = new->paint.compress;
1256 
1257     if (!XtIsRealized((Widget) new))
1258 	return ret;
1259 
1260     if (cur->paint.fillRule != new->paint.fillRule)
1261 	XSetFillStyle(XtDisplay(new), new->paint.fgc, new->paint.fillRule);
1262     if (cur->paint.foreground != new->paint.foreground)
1263 	XSetForeground(XtDisplay(new), new->paint.fgc, new->paint.foreground);
1264     if (cur->paint.pattern != new->paint.pattern)
1265 	XSetTile(XtDisplay(new), new->paint.fgc, new->paint.pattern);
1266 
1267     if (cur->paint.lineFillRule != new->paint.lineFillRule)
1268 	XSetFillStyle(XtDisplay(new), new->paint.sgc, new->paint.lineFillRule);
1269     if (cur->paint.lineForeground != new->paint.lineForeground)
1270 	XSetForeground(XtDisplay(new),
1271 		       new->paint.sgc, new->paint.lineForeground);
1272     if (cur->paint.linePattern != new->paint.linePattern)
1273 	XSetTile(XtDisplay(new), new->paint.sgc, new->paint.linePattern);
1274 
1275     if (cur->paint.lineWidth != new->paint.lineWidth) {
1276 	XSetLineAttributes(XtDisplay(new), new->paint.fgc,
1277 			   new->paint.lineWidth, LineSolid,
1278 			   CapRound, Global.join);
1279 	XSetLineAttributes(XtDisplay(new), new->paint.sgc,
1280 			   new->paint.lineWidth, LineSolid,
1281 			   CapRound, Global.join);
1282     }
1283 
1284     if (cur->paint.drawWidth != new->paint.drawWidth ||
1285 	cur->paint.drawHeight != new->paint.drawHeight) {
1286 	UndoStack *cur;
1287 	int gotit = 0;
1288 
1289 	/*
1290 	**  Resize the undo buffers
1291 	 */
1292 	if (new->paint.paint == None) {
1293 	    cur = new->paint.head;
1294 	    do {
1295 		if (cur->alphapix.pixmap == new->paint.current.pixmap)
1296 		    gotit = 1;
1297 		resizePixmap(new, &cur->alphapix);
1298 		if (gotit) {
1299 		    new->paint.current = cur->alphapix;
1300 		    gotit = 0;
1301 		}
1302 	    } while ((cur = cur->next) != new->paint.head);
1303 	    new->paint.undobot = new->paint.undoitems = 0;
1304 	    new->paint.redobot = new->paint.redoitems = 0;
1305 	}
1306 	/*
1307 	**  Destroy the XImage that is cached
1308 	 */
1309 	if (new->paint.image != NULL) {
1310 	    XDestroyImage(new->paint.image);
1311 	    XDestroyRegion(new->paint.imageRegion);
1312 	    new->paint.image = NULL;
1313 	}
1314 	if (new->paint.zoom>0 && XtMakeResizeRequest((Widget) new,
1315 				new->paint.drawWidth * new->paint.zoom,
1316 				new->paint.drawHeight * new->paint.zoom,
1317 				NULL, NULL) == XtGeometryDone) {
1318 	    ret = True;
1319 	    sizeChanged = True;
1320 	}
1321 	if (new->paint.zoom<0 && XtMakeResizeRequest((Widget) new,
1322                 (new->paint.drawWidth-new->paint.zoom-1)/(-new->paint.zoom),
1323                 (new->paint.drawHeight-new->paint.zoom-1)/(-new->paint.zoom),
1324 		NULL, NULL) == XtGeometryDone) {
1325 	    ret = True;
1326 	    sizeChanged = True;
1327 	}
1328 	for (i = 0; i < new->paint.paintChildrenSize; i++) {
1329 	    XtVaSetValues(new->paint.paintChildren[i],
1330 			  XtNdrawWidth, new->paint.drawWidth,
1331 			  XtNdrawHeight, new->paint.drawHeight,
1332 			  NULL);
1333 	}
1334     }
1335     if (cur->paint.zoom != new->paint.zoom) {
1336 	ret = True;
1337 
1338         if (new->paint.zoom>0)
1339 	    XtMakeResizeRequest((Widget) new,
1340 			    new->paint.drawWidth * new->paint.zoom,
1341 			    new->paint.drawHeight * new->paint.zoom,
1342 			    NULL, NULL);
1343         else {
1344 	    zoom = - new->paint.zoom;
1345 	    XtMakeResizeRequest((Widget) new,
1346 				(new->paint.drawWidth+zoom-1)/zoom,
1347 			        (new->paint.drawHeight+zoom-1)/zoom,
1348 			        NULL, NULL);
1349 	}
1350 	sizeChanged = True;
1351     }
1352     if (cur->paint.zoomX != new->paint.zoomX ||
1353 	cur->paint.zoomY != new->paint.zoomY) {
1354 	XExposeEvent event;
1355 
1356 	event.x = 0;
1357 	event.y = 0;
1358 	event.width = new->core.width;
1359 	event.height = new->core.height;
1360 
1361 	realExposeProc(new, &event, False);
1362 	PwRegionZoomPosChanged(new);
1363     }
1364     zoom = GET_ZOOM(new);
1365     if (cur->paint.grid != new->paint.grid) {
1366 	XRectangle *rect = GetRectangle(new);
1367 
1368 	PwDrawVisibleGrid(new, (Widget) new,
1369 			new->paint.grid,
1370 			rect->x, rect->y,
1371 			rect->x + rect->width,
1372                         rect->y + rect->height);
1373 
1374 	for (i = 0; i < new->paint.paintChildrenSize; i++) {
1375 	    XtVaSetValues(new->paint.paintChildren[i],
1376 			  XtNgrid, new->paint.grid,
1377 			  NULL);
1378 	}
1379     }
1380     if (cur->core.background_pixel != new->core.background_pixel)
1381 	XSetForeground(XtDisplay(new), new->paint.igc,
1382 		       new->core.background_pixel);
1383 
1384     if (cur->paint.cursor != new->paint.cursor)
1385 	XDefineCursor(XtDisplay(new), XtWindow(new), new->paint.cursor);
1386 
1387     /*
1388      * Number of undo levels changed.
1389      * Free old undo buffers and undo/redo stacks,
1390      * and allocate new ones. Catch: we need to preserve
1391      * the currently used undo buffer, otherwise we'll
1392      * lose everything on the canvas.
1393      */
1394     if (cur->paint.undoSize != new->paint.undoSize) {
1395 	UndoStack * this, * nxt, * first = NULL;
1396 
1397 	this = cur->paint.head;
1398 	do {
1399 	    nxt = this->next;
1400 	    if (this->alphapix.pixmap != cur->paint.current.pixmap) {
1401 		XFreePixmap(XtDisplay(new), this->alphapix.pixmap);
1402                 XtFree((char *)this->alphapix.alpha);
1403 	    }
1404 	    free(this);
1405 	    this = nxt;
1406 	} while (this != cur->paint.head);
1407 	new->paint.head = NULL;
1408 	for (i = 0; i <= new->paint.undoSize; i++) {
1409 	    this = undoBuffer(new);
1410 	    if (i == 0) {
1411 		first = this;
1412 		this->alphapix = cur->paint.current;
1413                 if (cur->paint.current.alpha) {
1414                     int m = cur->paint.drawWidth * cur->paint.drawHeight;
1415 		    if (!this->alphapix.alpha)
1416 		        this->alphapix.alpha = xmalloc(m);
1417                     memcpy(this->alphapix.alpha, cur->paint.current.alpha, m);
1418 		}
1419 	    } else {
1420 		this->alphapix.pixmap =
1421                     XCreatePixmap(XtDisplay(new), XtWindow(new),
1422 			          new->paint.drawWidth,
1423 				  new->paint.drawHeight,
1424 				  DefaultDepthOfScreen(XtScreen(new)));
1425 		XFillRectangle(XtDisplay(new), this->alphapix.pixmap,
1426 			       new->paint.igc, 0, 0,
1427 			       new->paint.drawWidth, new->paint.drawHeight);
1428                 if (this->alphapix.alpha)
1429 		    memset(this->alphapix.alpha,
1430                            (unsigned char) Global.alpha_bg,
1431                            new->paint.drawWidth * new->paint.drawHeight);
1432 	    }
1433 	}
1434 	first->next = new->paint.head;
1435 	new->paint.current = cur->paint.current;
1436 	new->paint.undo = new->paint.head;
1437 	free(cur->paint.undostack);
1438 	free(cur->paint.redostack);
1439 	UndoInitialize(new, new->paint.undoSize);
1440     }
1441 
1442     if (sizeChanged)
1443 	XtCallCallbackList((Widget) new, new->paint.sizecalls, NULL);
1444 
1445     return ret;
1446 }
1447 
1448 static void
GetValuesHook(Widget w,ArgList args,Cardinal * nargs)1449 GetValuesHook(Widget w, ArgList args, Cardinal * nargs)
1450 {
1451     PaintWidget pw = (PaintWidget) w;
1452     PaintWidget pp = (PaintWidget) pw->paint.paint;
1453     Arg a;
1454     int i;
1455 
1456     if (pp == None)
1457 	return;
1458 
1459     for (i = 0; i < *nargs; i++) {
1460 	char *nm = args[i].name;
1461 
1462 	if (strcmp(nm, XtNlineWidth) == 0)
1463 	    XtSetArg(a, XtNlineWidth, args[i].value);
1464 	else if (strcmp(nm, XtNlineFillRule) == 0)
1465 	    XtSetArg(a, XtNlineFillRule, args[i].value);
1466 	else if (strcmp(nm, XtNfillRule) == 0)
1467 	    XtSetArg(a, XtNfillRule, args[i].value);
1468 	else if (strcmp(nm, XtNdrawWidth) == 0)
1469 	    XtSetArg(a, XtNdrawWidth, args[i].value);
1470 	else if (strcmp(nm, XtNdrawHeight) == 0)
1471 	    XtSetArg(a, XtNdrawHeight, args[i].value);
1472 	else
1473 	    continue;
1474 	XtGetValues((Widget) pp, &a, 1);
1475     }
1476 }
1477 
1478 static int
QueryGeometryProc(Widget w,XtWidgetGeometry * proposed,XtWidgetGeometry * reply)1479 QueryGeometryProc(Widget w, XtWidgetGeometry * proposed,
1480 		  XtWidgetGeometry * reply)
1481 {
1482 
1483 /*
1484 **  Use the fact that the return values are ordered by "importance"
1485  */
1486 #define SETRET(ret,x)	ret = (x > ret) ? x : ret
1487     PaintWidget pw = (PaintWidget) w;
1488     int width;
1489     int height;
1490 
1491     if (pw->paint.zoom>0) {
1492         width = pw->paint.drawWidth * pw->paint.zoom;
1493         height = pw->paint.drawHeight * pw->paint.zoom;
1494     } else {
1495         width = (pw->paint.drawWidth-pw->paint.zoom-1)/(-pw->paint.zoom);
1496         height = (pw->paint.drawHeight-pw->paint.zoom-1)/(-pw->paint.zoom);
1497     }
1498     reply->request_mode = CWWidth | CWHeight;
1499     reply->width = width;
1500     reply->height = height;
1501 
1502     if (((proposed->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight))
1503 	&& (proposed->width == reply->width)
1504 	&& (proposed->height == reply->height))
1505 	return XtGeometryNo;
1506     else
1507 	return XtGeometryAlmost;
1508 }
1509 
1510 /*
1511  * Convenience routine (with caching) to get an XImage of an area
1512  */
1513 XImage *
PwGetImage(Widget w,XRectangle * rect)1514 PwGetImage(Widget w, XRectangle * rect)
1515 {
1516     PaintWidget pw = (PaintWidget) w;
1517     Pixmap pix = GET_PIXMAP(pw);
1518     Region r;
1519     XRectangle clean;
1520 
1521     if (pw->paint.paint != None)
1522 	pw = (PaintWidget) pw->paint.paint;
1523 
1524 
1525     if (rect != NULL) {
1526 	if (rect->x < 0) {
1527 	    clean.x = 0;
1528 	    clean.width = rect->width + rect->x;
1529 	} else {
1530 	    clean.x = rect->x;
1531 	    clean.width = rect->width;
1532 	}
1533 	if (rect->y < 0) {
1534 	    clean.y = 0;
1535 	    clean.height = rect->height + rect->y;
1536 	} else {
1537 	    clean.y = rect->y;
1538 	    clean.height = rect->height;
1539 	}
1540 	if (clean.width > pw->paint.drawWidth)
1541 	    clean.width = pw->paint.drawWidth;
1542 	if (clean.height > pw->paint.drawHeight)
1543 	    clean.height = pw->paint.drawHeight;
1544     } else {
1545 	clean.x = 0;
1546 	clean.y = 0;
1547 	clean.width = pw->paint.drawWidth;
1548 	clean.height = pw->paint.drawHeight;
1549     }
1550 
1551     if (pw->paint.image == NULL) {
1552 	pw->paint.image = XCreateImage(XtDisplay(w), pw->paint.visual,
1553 				       pw->core.depth, ZPixmap, 0, NULL,
1554 				       pw->paint.drawWidth, pw->paint.drawHeight,
1555 				       32, 0);
1556 	pw->paint.image->data = (char *)
1557 	    xmalloc(pw->paint.drawHeight * pw->paint.image->bytes_per_line);
1558 	pw->paint.imageRegion = XCreateRegion();
1559 	pw->paint.invalidateRegion = False;
1560     }
1561     if (pw->paint.invalidateRegion) {
1562 	XDestroyRegion(pw->paint.imageRegion);
1563 	pw->paint.imageRegion = XCreateRegion();
1564 	pw->paint.invalidateRegion = False;
1565     }
1566     if (XRectInRegion(pw->paint.imageRegion, clean.x, clean.y,
1567 		      clean.width, clean.height) == RectangleIn)
1568 	return pw->paint.image;
1569 
1570     r = XCreateRegion();
1571     XUnionRectWithRegion(&clean, r, r);
1572     XSubtractRegion(r, pw->paint.imageRegion, r);
1573 
1574     XClipBox(r, &clean);
1575 
1576     /*
1577     **	Since this is "caching" grow the image slightly over the
1578     **	  requested size.
1579      */
1580     if ((clean.x -= 8) < 0)
1581 	clean.x = 0;
1582     if ((clean.y -= 8) < 0)
1583 	clean.y = 0;
1584     if ((clean.width += 16) > pw->paint.drawWidth - clean.x)
1585 	clean.width = pw->paint.drawWidth - clean.x;
1586     if ((clean.height += 16) > pw->paint.drawHeight - clean.y)
1587 	clean.height = pw->paint.drawHeight - clean.y;
1588 
1589     XGetSubImage(XtDisplay(pw), pix, clean.x, clean.y,
1590 		 clean.width, clean.height, AllPlanes, ZPixmap,
1591 		 pw->paint.image, clean.x, clean.y);
1592     XUnionRectWithRegion(&clean, pw->paint.imageRegion,
1593 			 pw->paint.imageRegion);
1594 
1595     XDestroyRegion(r);
1596 
1597     return pw->paint.image;
1598 }
1599 
1600 /*  Get a copy of the pixmap of the current canvas image */
1601 void
PwGetPixmap(Widget w,Pixmap * pix,int * width,int * height)1602 PwGetPixmap(Widget w, Pixmap * pix, int *width, int *height)
1603 {
1604     PaintWidget pw = (PaintWidget) w;
1605     *pix = None;
1606 
1607     if (pw->paint.paint != None) {
1608 	PwGetPixmap((Widget) pw->paint.paint, pix, width, height);
1609 	return;
1610     }
1611 
1612     if (width != NULL)
1613 	*width = pw->paint.drawWidth;
1614     if (height != NULL)
1615 	*height = pw->paint.drawHeight;
1616 
1617     *pix = XCreatePixmap(XtDisplay(w), XtWindow(w),
1618 			 pw->paint.drawWidth, pw->paint.drawHeight,
1619 			 pw->core.depth);
1620 
1621     if (*pix != None)
1622         XCopyArea(XtDisplay(w), GET_PIXMAP(pw), *pix, pw->paint.gc,
1623 	          0, 0, pw->paint.drawWidth, pw->paint.drawHeight, 0, 0);
1624 }
1625 
1626 /*  Get the pixmap id of the current canvas image */
1627 Pixmap
PwGetRawPixmap(Widget w)1628 PwGetRawPixmap(Widget w)
1629 {
1630     PaintWidget pw = (PaintWidget) w;
1631 
1632     if (pw->paint.paint != None)
1633 	return PwGetRawPixmap((Widget) pw->paint.paint);
1634 
1635     return GET_PIXMAP(pw);
1636 }
1637 
1638 static void
pwSetPixmap(PaintWidget w,Pixmap pix,int flag)1639 pwSetPixmap(PaintWidget w, Pixmap pix, int flag)
1640 {
1641     Window root;
1642     int x, y;
1643     unsigned int width, height, bw, depth;
1644 
1645     XGetGeometry(XtDisplay(w), pix,
1646 		 &root, &x, &y, &width, &height, &bw, &depth);
1647 
1648     XCopyArea(XtDisplay(w), pix, GET_PIXMAP(w),
1649 	      w->paint.gc, 0, 0, width, height, 0, 0);
1650 }
1651 
1652 static void
fatCallback(Widget parent,XtPointer w,XtPointer rectArg)1653 fatCallback(Widget parent, XtPointer w, XtPointer rectArg)
1654 {
1655     XRectangle *rect = (XRectangle *) rectArg;
1656     PaintWidget pw = (PaintWidget) w;
1657     static XExposeEvent event;
1658     int zoom = GET_ZOOM(pw);
1659 
1660     /*
1661     **	Make this look like an expose event on the fatbits region
1662      */
1663 
1664     if (zoom>0) {
1665         event.x = (rect->x - pw->paint.zoomX) * zoom;
1666         event.y = (rect->y - pw->paint.zoomY) * zoom;
1667         event.width = rect->width * zoom;
1668         event.height = rect->height * zoom;
1669     } else {
1670         event.x = (rect->x - pw->paint.zoomX) / (-zoom);
1671         event.y = (rect->y - pw->paint.zoomY) / (-zoom);
1672         event.width = (rect->width-zoom-1) / (-zoom);
1673         event.height = (rect->height-zoom-1) / (-zoom);
1674     }
1675 
1676     realExposeProc(pw, &event, False);
1677 }
1678 
1679 /*
1680  * If rect is NULL, use undo box size.
1681  */
1682 void
PwUpdate(Widget w,XRectangle * rect,Boolean force)1683 PwUpdate(Widget w, XRectangle * rect, Boolean force)
1684 {
1685     PaintWidget pw = (PaintWidget) w;
1686     PaintWidget parent = (PaintWidget) pw->paint.paint;
1687     PaintWidget usePW = (parent == None) ? pw : parent;
1688     XRectangle all;
1689 
1690     if (rect == NULL) {
1691 	if (pw->paint.undo == NULL) {
1692 	    all.x = 0;
1693 	    all.y = 0;
1694 	    all.width = pw->core.width;
1695 	    all.height = pw->core.height;
1696 	    rect = &all;
1697 	} else {
1698 	    rect = &pw->paint.undo->box;
1699 	}
1700     } else {
1701 	all.x = rect->x - pw->paint.lineWidth;
1702 	all.y = rect->y - pw->paint.lineWidth;
1703 	all.width = rect->width + pw->paint.lineWidth * 2 + 1;
1704 	all.height = rect->height + pw->paint.lineWidth * 2 + 1;
1705 	rect = &all;
1706     }
1707 
1708     /*
1709     **	If we have a caching image
1710      */
1711     if (usePW->paint.image != NULL && !usePW->paint.invalidateRegion)
1712 	usePW->paint.invalidateRegion = True;
1713 
1714     XtCallCallbackList((Widget) usePW, usePW->paint.fatcalls,
1715 		       (XtPointer) rect);
1716 
1717     /* ugly hack to update alpha channel... */
1718     if (usePW->paint.current.alpha) {
1719         XImage *xim, *ximp;
1720         int x, y, x1, y1, x2, y2;
1721         Pixmap pix, pixp;
1722         unsigned char c;
1723         if (usePW->paint.undostack == NULL) goto finish;
1724         if (usePW->paint.undoitems <= 0) goto finish;
1725         x = getIndexOp();
1726         if (1 << x != Global.operation) goto finish;
1727         if ((x%3)==2 && x>=14 && x<=26) goto finish;
1728         if (x==11)
1729 	    c = (unsigned char)Global.alpha_bg;
1730         else
1731 	    c = (unsigned char)Global.alpha_fg;
1732         x1 = rect->x;
1733         if (x1<0) x1 = 0;
1734         if (x1>usePW->paint.drawWidth) x1 = usePW->paint.drawWidth;
1735         x2 = rect->x+rect->width;
1736         if (x2<0) x2 = 0;
1737         if (x2>usePW->paint.drawWidth) x2 = usePW->paint.drawWidth;
1738         x2 = x2-x1;
1739         if (x2<0) { x1 = x1+x2; x2 = -x2; }
1740         y1 = rect->y;
1741         if (y1<0) y1 = 0;
1742         if (y1>usePW->paint.drawHeight) y1 = usePW->paint.drawHeight;
1743         y2 = rect->y+rect->height;
1744         if (y2<0) y2 = 0;
1745         if (y2>usePW->paint.drawHeight) y2 = usePW->paint.drawHeight;
1746         y2 = y2-y1;
1747         if (y2<0) { y1 = y1+y2; y2 = -y2; }
1748         if (x2==0 || y2==0) goto finish;
1749         pix = GET_PIXMAP(usePW);
1750         if (!pix) goto finish;
1751         x = (usePW->paint.undobot+usePW->paint.undoitems-1) % usePW->paint.nlevels;
1752         pixp = usePW->paint.undostack[x].pixmap;
1753         if (!pixp) goto finish;
1754         xim = XGetImage(XtDisplay(w), pix, x1, y1, x2, y2, AllPlanes, ZPixmap);
1755         if (!xim) goto finish;
1756         ximp = XGetImage(XtDisplay(w), pixp, x1, y1, x2, y2, AllPlanes,ZPixmap);
1757         if (!ximp) goto finishp;
1758         for (y = 0; y < y2; y++)
1759 	    for (x = 0; x < x2; x++) {
1760 	        if ((xxGetPixel(xim, x, y)) !=  (xxGetPixel(ximp, x, y)))
1761  	     usePW->paint.current.alpha[(x+x1)+(y+y1)*usePW->paint.drawWidth]=c;
1762 	    }
1763 	XDestroyImage(ximp);
1764     finishp:
1765 	XDestroyImage(xim);
1766     }
1767 
1768     finish:
1769     if (force || (abs(pw->paint.zoom)>1) || parent ||
1770         (pw->paint.current.alpha && pw->paint.alpha_mode)) {
1771         if (pw->paint.zoom>1 && usePW!=pw) {
1772            XExposeEvent event;
1773 	   /*
1774            event.x = (rect->x - pw->paint.zoomX) * pw->paint.zoom;
1775 	   event.y = (rect->y - pw->paint.zoomY) * pw->paint.zoom;
1776            event.width = rect->width * pw->paint.zoom;
1777            event.height = rect->height * pw->paint.zoom;
1778 	   */
1779            /* JPD : curious hack - don't know why this is necessary... */
1780            event.x = 0;
1781            event.y = 0;
1782            XtVaGetValues((Widget)pw,
1783                          XtNwidth, &event.width, XtNheight, &event.height,
1784                          NULL);
1785            realExposeProc(pw, &event, False);
1786 	} else
1787            fatCallback((Widget) usePW, (XtPointer) pw, rect);
1788     }
1789 
1790     if (usePW->paint.grid)
1791 	PwDrawVisibleGrid(usePW, w, True, rect->x, rect->y,
1792                           rect->x + rect->width, rect->y + rect->height);
1793 
1794     XSync(XtDisplay(pw), False);
1795 }
1796 
1797 /*
1798 **  Bogus XXX
1799  */
1800 XRectangle *
PwScaleRectangle(Widget w,XRectangle * src)1801 PwScaleRectangle(Widget w, XRectangle * src)
1802 {
1803     return src;
1804 }
1805 
1806 void
PwPutPixmap(Widget w,Pixmap pix)1807 PwPutPixmap(Widget w, Pixmap pix)
1808 {
1809     PaintWidget pw = (PaintWidget) w;
1810     GC gc = pw->paint.gc;
1811     AlphaPixmap dst;
1812     Window root;
1813     int x, y;
1814     unsigned int width, height, bw, depth;
1815     XRectangle rect;
1816 
1817     XGetGeometry(XtDisplay(w), pix, &root, &x, &y, &width, &height, &bw, &depth);
1818     rect.x = 0;
1819     rect.y = 0;
1820     rect.width = width;
1821     rect.height = height;
1822     dst = PwUndoStart(w, &rect);
1823     XCopyArea(XtDisplay(pw), pix, dst.pixmap, gc, 0, 0,
1824 	      width, height, 0, 0);
1825     if (pw->paint.current.alpha)
1826         memcpy(dst.alpha, pw->paint.current.alpha, width*height);
1827     PwUpdate(w, &rect, True);
1828 }
1829 
1830 static void
removeChild(Widget child,Widget w)1831 removeChild(Widget child, Widget w)
1832 {
1833     PaintWidget pw = (PaintWidget) w;
1834     int i;
1835 
1836     for (i = 0; i < pw->paint.paintChildrenSize; i++)
1837 	if (pw->paint.paintChildren[i] == child)
1838 	    break;
1839     for (i++; i < pw->paint.paintChildrenSize; i++)
1840 	pw->paint.paintChildren[i - 1] = pw->paint.paintChildren[i];
1841 
1842     pw->paint.paintChildrenSize--;
1843 
1844     XtRemoveCallback((Widget) w, XtNfatBack, fatCallback, (XtPointer) child);
1845 }
1846 
1847 void
PwAddChild(Widget w,Widget child)1848 PwAddChild(Widget w, Widget child)
1849 {
1850     PaintWidget pw = (PaintWidget) w;
1851 
1852     if (pw->paint.paintChildren == NULL)
1853 	pw->paint.paintChildren = (Widget *)
1854 	    xmalloc(sizeof(Widget) * (pw->paint.paintChildrenSize + 2));
1855     else
1856 	pw->paint.paintChildren = (Widget *)
1857 	    XtRealloc((XtPointer) pw->paint.paintChildren,
1858 		      sizeof(Widget) * (pw->paint.paintChildrenSize + 2));
1859     pw->paint.paintChildren[pw->paint.paintChildrenSize++] = child;
1860     XtAddCallback(child, XtNdestroyCallback, (XtCallbackProc) removeChild,
1861 		  (XtPointer) w);
1862     XtAddCallback(w, XtNfatBack, fatCallback, (XtPointer) child);
1863 }
1864