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 ▭
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