home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xpaint-247 / paint.c < prev    next >
C/C++ Source or Header  |  1996-06-25  |  42KB  |  1,470 lines

  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 1996/06/19 19:02:29 torsten 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 <stdio.h>
  25. #include <stdlib.h>
  26.  
  27. #include "PaintP.h"
  28. #include "xpaint.h"
  29. #include "misc.h"
  30.  
  31. /*
  32. **  Value at which zoom starts putting in "white" lines
  33. **    between pixels
  34.  */
  35. #define ZOOM_THRESH 5
  36.  
  37.  
  38. typedef void (*func_t) (Widget, void *, XEvent *, Boolean);
  39. typedef struct data_s {
  40.     func_t func;
  41.     void *data;
  42.     int mask, flag;
  43.     struct data_s *next;
  44. } data_t;
  45.  
  46. void PwAddChild(Widget, Widget);
  47.  
  48. static void pwSetPixmap(PaintWidget w, Pixmap pix, int flag);
  49. static void fatCallback(Widget, XtPointer, XtPointer);
  50. static void realExposeProc(PaintWidget, XExposeEvent *, Boolean);
  51. static void drawVisibleGrid(PaintWidget, Widget, Boolean,
  52.                 int, int, int, int, int);
  53.  
  54. static XtResource resources[] =
  55. {
  56. #define offset(field) XtOffset(PaintWidget, paint.field)
  57.     /* {name, class, type, size, offset, default_type, default_addr}, */
  58.     {XtNcompress, XtCCompress, XtRBoolean, sizeof(Boolean),
  59.      offset(compress), XtRImmediate, (XtPointer) False},
  60.     {XtNreadOnly, XtCReadOnly, XtRBoolean, sizeof(Boolean),
  61.      offset(compress), XtRImmediate, (XtPointer) False},
  62.     {XtNdrawWidth, XtCDrawWidth, XtRInt, sizeof(int),
  63.      offset(drawWidth), XtRImmediate, (XtPointer) 512},
  64.     {XtNdrawHeight, XtCDrawHeight, XtRInt, sizeof(int),
  65.      offset(drawHeight), XtRImmediate, (XtPointer) 512},
  66.     {XtNlineWidth, XtCLineWidth, XtRInt, sizeof(int),
  67.      offset(lineWidth), XtRImmediate, (XtPointer) 0},
  68.     {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
  69.      offset(fontInfo), XtRString, XtDefaultFont},
  70.     {XtNpattern, XtCPattern, XtRPixmap, sizeof(Pixmap),
  71.      offset(pattern), XtRPixmap, (XtPointer) None},
  72.     {XtNlinePattern, XtCLinePattern, XtRPixmap, sizeof(Pixmap),
  73.      offset(linePattern), XtRPixmap, (XtPointer) None},
  74.     {XtNpixmap, XtCPixmap, XtRPixmap, sizeof(Pixmap),
  75.      offset(sourcePixmap), XtRPixmap, (XtPointer) NULL},
  76.     {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  77.      offset(foreground), XtRString, XtDefaultForeground},
  78.     {XtNlineForeground, XtCLineForeground, XtRPixel, sizeof(Pixel),
  79.      offset(lineForeground), XtRString, XtDefaultForeground},
  80.     {XtNsnap, XtCSnap, XtRInt, sizeof(int),
  81.      offset(snap), XtRImmediate, (XtPointer) 10},
  82.     {XtNregionCallback, XtCRegionCallback, XtRCallback, sizeof(XtPointer),
  83.      offset(regionCalls), XtRCallback, (XtPointer) None},
  84.     {XtNsizeChanged, XtCSizeChanged, XtRCallback, sizeof(XtPointer),
  85.      offset(sizecalls), XtRCallback, (XtPointer) None},
  86.     {XtNfatBack, XtCFatBack, XtRCallback, sizeof(XtPointer),
  87.      offset(fatcalls), XtRCallback, (XtPointer) None},
  88.     {XtNundoSize, XtCUndoSize, XtRInt, sizeof(int),
  89.      offset(undoSize), XtRImmediate, (XtPointer) 1},
  90.     {XtNzoom, XtCZoom, XtRInt, sizeof(int),
  91.      offset(zoom), XtRImmediate, (XtPointer) 1},
  92.     {XtNzoomX, XtCZoomX, XtRInt, sizeof(int),
  93.      offset(zoomX), XtRImmediate, (XtPointer) 0},
  94.     {XtNzoomY, XtCZoomY, XtRInt, sizeof(int),
  95.      offset(zoomY), XtRImmediate, (XtPointer) 0},
  96.     {XtNgrid, XtCGrid, XtRBoolean, sizeof(Boolean),
  97.      offset(grid), XtRImmediate, (XtPointer) False},
  98.     {XtNsnapOn, XtCSnapOn, XtRBoolean, sizeof(Boolean),
  99.      offset(snapOn), XtRImmediate, (XtPointer) False},
  100.     {XtNpaint, XtCPaint, XtRWidget, sizeof(Widget),
  101.      offset(paint), XtRImmediate, (XtPointer) None},
  102.     {XtNdirty, XtCDirty, XtRBoolean, sizeof(Boolean),
  103.      offset(dirty), XtRImmediate, (XtPointer) False},
  104.     {XtNfillRule, XtCFillRule, XtRInt, sizeof(int),
  105.      offset(fillRule), XtRImmediate, (XtPointer) FillSolid},
  106.     {XtNlineFillRule, XtCLineFillRule, XtRInt, sizeof(int),
  107.      offset(lineFillRule), XtRImmediate, (XtPointer) FillSolid},
  108.     {XtNdownX, XtCDownX, XtRPosition, sizeof(Position),
  109.      offset(downX), XtRImmediate, (XtPointer) 0},
  110.     {XtNdownY, XtCDownY, XtRPosition, sizeof(Position),
  111.      offset(downY), XtRImmediate, (XtPointer) 0},
  112.     {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
  113.      offset(cursor), XtRString, (XtPointer) "watch"},
  114.     {XtNfilename, XtCfilename, XtRString, sizeof(String),
  115.      offset(filename), XtRString, (XtPointer) 0},
  116.     {XtNmenuwidgets, XtCmenuwidgets, XtRWidgetList, sizeof(WidgetList),
  117.      offset(menuwidgets), XtRWidgetList, (XtPointer) 0}
  118. #undef offset
  119. };
  120.  
  121. /*
  122. **  Some forward defines.
  123.  */
  124. static void InitializeProc(Widget, Widget);
  125. static void DestroyProc(Widget);
  126. static void ResizeProc(Widget);
  127. static void ExposeProc(Widget, XExposeEvent *);
  128. static void RealizeProc(Widget, Mask *, XSetWindowAttributes *);
  129. static Boolean SetValuesProc(Widget, Widget, Widget);
  130. static void GetValuesHook(Widget, ArgList, Cardinal *);
  131. static int QueryGeometryProc(Widget w, XtWidgetGeometry * proposed,
  132.                  XtWidgetGeometry * reply);
  133.  
  134. static XtGeometryResult
  135. GeometryManager(Widget w, XtWidgetGeometry * request, XtWidgetGeometry * reply)
  136. {
  137.     *reply = *request;
  138.  
  139.     if ((request->request_mode & CWX) != 0)
  140.     w->core.x = request->x;
  141.     if ((request->request_mode & CWY) != 0)
  142.     w->core.y = request->y;
  143.     if ((request->request_mode & CWWidth) != 0)
  144.     w->core.width = request->width;
  145.     if ((request->request_mode & CWHeight) != 0)
  146.     w->core.height = request->height;
  147.     if ((request->request_mode & CWBorderWidth) != 0)
  148.     w->core.border_width = request->border_width;
  149.  
  150.     return XtGeometryYes;
  151. }
  152.  
  153.  
  154. PaintClassRec paintClassRec =
  155. {
  156.     {                /* core fields */
  157.     /* superclass        */ (WidgetClass) & compositeClassRec,
  158.     /* class_name        */ "Paint",
  159.     /* widget_size        */ sizeof(PaintRec),
  160.     /* class_initialize        */ NULL,
  161.     /* class_part_initialize    */ NULL,
  162.     /* class_inited        */ FALSE,
  163.     /* initialize        */ (XtInitProc) InitializeProc,
  164.     /* initialize_hook        */ NULL,
  165.     /* realize            */ RealizeProc,
  166.     /* actions            */ NULL,
  167.     /* num_actions        */ 0,
  168.     /* resources        */ resources,
  169.     /* num_resources        */ XtNumber(resources),
  170.     /* xrm_class        */ NULLQUARK,
  171.     /* compress_motion        */ FALSE,
  172.     /* compress_exposure    */ TRUE,
  173.     /* compress_enterleave    */ TRUE,
  174.     /* visible_interest        */ FALSE,
  175.     /* destroy            */ DestroyProc,
  176.     /* resize            */ ResizeProc,
  177.     /* expose            */ (XtExposeProc) ExposeProc,
  178.     /* set_values        */ (XtSetValuesFunc) SetValuesProc,
  179.     /* set_values_hook        */ NULL,
  180.     /* set_values_almost    */ XtInheritSetValuesAlmost,
  181.     /* get_values_hook        */ GetValuesHook,
  182.     /* accept_focus        */ NULL,
  183.     /* version            */ XtVersion,
  184.     /* callback_private        */ NULL,
  185.     /* tm_table            */ NULL,
  186.     /* query_geometry        */ (XtGeometryHandler) QueryGeometryProc,
  187.     /* display_accelerator    */ XtInheritDisplayAccelerator,
  188.     /* extension        */ NULL
  189.     },
  190.     {                /* composite fields        */
  191.     /* geometry_manager        */ GeometryManager,
  192.     /* change_managed        */ XtInheritChangeManaged,
  193.     /* insert_child        */ XtInheritInsertChild,
  194.     /* delete_childion        */ XtInheritDeleteChild,
  195.     /* extension        */ NULL,
  196.     },
  197.     {                /* paint fields */
  198.     0
  199.     }
  200. };
  201.  
  202. WidgetClass paintWidgetClass = (WidgetClass) & paintClassRec;
  203.  
  204. /*
  205.  * Attach a new undo buffer to the head of the undo list for this widget.
  206.  */
  207. static UndoStack *
  208. undoBuffer(PaintWidget w)
  209. {
  210.     UndoStack *new = (UndoStack *) XtMalloc(sizeof(UndoStack));
  211.  
  212.     if (new == NULL)
  213.     return NULL;
  214.  
  215.     new->box.x = 0;
  216.     new->box.y = 0;
  217.     new->box.width = 0;
  218.     new->box.height = 0;
  219.     new->pixmap = None;
  220.     new->next = w->paint.head;
  221.     new->pushed = False;
  222.     w->paint.head = new;
  223.  
  224.     return new;
  225. }
  226.  
  227. static void
  228. InitializeProc(Widget w, Widget newArg)
  229. {
  230.     PaintWidget new = (PaintWidget) newArg;
  231.     int i;
  232.     int zoom = new->paint.zoom;
  233.     UndoStack * cur;
  234.  
  235.     if (zoom == PwZoomParent && new->paint.paint == None)
  236.     zoom = new->paint.zoom = 1;
  237.  
  238.     if (zoom == PwZoomParent)
  239.     zoom = 1;
  240.     else if (zoom < 0)
  241.     zoom = new->paint.zoom = 1;
  242.  
  243.     if (new->paint.sourcePixmap != None) {
  244.     Window root;
  245.     int x, y;
  246.     unsigned int width, height, bw, depth;
  247.  
  248.     XGetGeometry(XtDisplay(w), new->paint.sourcePixmap,
  249.              &root, &x, &y, &width, &height, &bw, &depth);
  250.  
  251.     new->paint.drawWidth = width;
  252.     new->paint.drawHeight = height;
  253.     } else if (new->paint.paint != None) {
  254.     PaintWidget parent = (PaintWidget) new->paint.paint;
  255.  
  256.     new->paint.drawWidth = parent->paint.drawWidth;
  257.     new->paint.drawHeight = parent->paint.drawHeight;
  258.     }
  259.     if (new->core.width == 0)
  260.     new->core.width = new->paint.drawWidth * zoom;
  261.     if (new->core.height == 0)
  262.     new->core.height = new->paint.drawHeight * zoom;
  263.  
  264.     new->paint.foreground = BlackPixelOfScreen(XtScreen(new));
  265.     new->paint.background = WhitePixelOfScreen(XtScreen(new));
  266.  
  267.     new->paint.gc = None;
  268.     new->paint.igc = None;
  269.     new->paint.sgc = None;
  270.     new->paint.fgc = None;
  271.     new->paint.mgc = None;
  272.     new->paint.xgc = None;
  273.     new->paint.tgc = None;
  274.  
  275.     /*
  276.     **    Init the undo stuff
  277.      */
  278.     new->paint.head = NULL;
  279.     if (new->paint.paint == None) {
  280.     cur = undoBuffer(new);
  281.     for (i = 0; i <= new->paint.undoSize; i++)
  282.         undoBuffer(new);
  283.     cur->next = new->paint.head;
  284.     UndoInitialize(new, new->paint.undoSize);
  285.     new->paint.undo = new->paint.head;
  286.     new->paint.current = new->paint.head->pixmap;
  287.     } else {
  288.     new->paint.undo = NULL;
  289.     new->paint.current = None;
  290.     }
  291.  
  292.     /*
  293.     **    The region information
  294.      */
  295.     new->paint.region.isVisible = False;
  296.     new->paint.region.mask = None;
  297.     new->paint.region.source = None;
  298.     new->paint.region.notMask = None;
  299.     new->paint.region.fg_gc = None;
  300.     new->paint.region.bg_gc = None;
  301.     new->paint.region.child = None;
  302.     new->paint.region.sourceImg = NULL;
  303.     new->paint.region.maskImg = NULL;
  304.     new->paint.region.notMaskImg = NULL;
  305.     new->paint.region.proc = NULL;
  306.  
  307.     for (i = 0; i < XtNumber(new->paint.region.grip); i++)
  308.     new->paint.region.grip[i] = None;
  309.  
  310.     /*
  311.     **    Now the backing store image
  312.      */
  313.     new->paint.image = NULL;
  314.  
  315.     /*
  316.     **
  317.      */
  318.     new->paint.paintChildrenSize = 0;
  319.     new->paint.paintChildren = NULL;
  320.     new->paint.filename = NULL;
  321.     new->paint.menuwidgets = NULL;
  322. }
  323.  
  324. static XRectangle *
  325. GetRectangle(PaintWidget w)
  326. {
  327.     static XRectangle rect;
  328.     XRectangle *rp = &rect, newRect;
  329.     Widget cur;
  330.     Widget prev = (Widget) w;
  331.     int dx, dy;
  332.  
  333.     rect.x = dx = 0;
  334.     rect.y = dy = 0;
  335.     rect.width = w->core.width - dx;
  336.     rect.height = w->core.height - dy;
  337.  
  338.     /*
  339.     **    Climb the tree to find the visible area.
  340.     **
  341.      */
  342.     for (cur = XtParent((Widget) w); !XtIsShell(cur); cur = XtParent(cur)) {
  343.     dx += -prev->core.x;
  344.     dy += -prev->core.y;
  345.     newRect.x = dx;
  346.     newRect.y = dy;
  347.     newRect.width = cur->core.width;
  348.     newRect.height = cur->core.height;
  349.  
  350.     rp = RectIntersect(&newRect, rp);
  351.  
  352.     prev = cur;
  353.     }
  354.  
  355.     if (rp != NULL)
  356.     rect = *rp;
  357.     else
  358.     rect.x = rect.y = rect.width = rect.height = 0;
  359.  
  360.     return ▭
  361. }
  362.  
  363. static void
  364. RealizeProc(Widget w, Mask * valueMask,
  365.         XSetWindowAttributes * attributes)
  366. {
  367.     XWindowAttributes wattr;
  368.     PaintWidget pw = (PaintWidget) w;
  369.     PaintWidget pp = (PaintWidget) pw->paint.paint;
  370.     UndoStack *cur;
  371.     Window root;
  372.     int x, y, i;
  373.     unsigned int width, height, bw, depth;
  374.     XGCValues values;
  375.  
  376.     XtCreateWindow(w, InputOutput, CopyFromParent, *valueMask, attributes);
  377.  
  378.     XGetGeometry(XtDisplay(w), XtWindow(w),
  379.          &root, &x, &y, &width, &height, &bw, &depth);
  380.  
  381.     values.foreground = pw->paint.foreground;
  382.     values.background = pw->core.background_pixel;
  383.     pw->paint.gc = XtGetGC(w, GCForeground | GCBackground, &values);
  384.  
  385.     if (pp == None) {
  386.     /*
  387.     **  Inverse of the base colors.
  388.      */
  389.     values.foreground = pw->core.background_pixel;
  390.     values.background = pw->paint.foreground;
  391.     pw->paint.igc = XCreateGC(XtDisplay(w), XtWindow(w),
  392.                   GCForeground | GCBackground, &values);
  393.     pw->paint.tgc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
  394.  
  395.     values.function = GXxor;
  396.     values.foreground = ~0;
  397.     values.subwindow_mode = IncludeInferiors;
  398.     pw->paint.xgc = XCreateGC(XtDisplay(w), XtWindow(w),
  399.            GCForeground | GCFunction | GCSubwindowMode, &values);
  400.     } else {
  401.     pw->paint.igc = pp->paint.igc;
  402.     pw->paint.tgc = pp->paint.tgc;
  403.     pw->paint.xgc = pp->paint.xgc;
  404.  
  405.     pw->paint.lineWidth = pp->paint.lineWidth;
  406.     }
  407.  
  408.     /*
  409.     **    Create the filled gc information
  410.      */
  411.     if (pw->paint.paint == None) {
  412.     pw->paint.sgc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
  413.     pw->paint.fgc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
  414.     XSetForeground(XtDisplay(w), pw->paint.fgc, pw->paint.foreground);
  415.     XSetForeground(XtDisplay(w), pw->paint.sgc, pw->paint.lineForeground);
  416.  
  417.     /*
  418.     **  First the fill GC
  419.      */
  420.     XSetFillStyle(XtDisplay(w), pw->paint.fgc, pw->paint.fillRule);
  421.     XSetLineAttributes(XtDisplay(w), pw->paint.fgc,
  422.                pw->paint.lineWidth, LineSolid,
  423.                CapRound, JoinMiter);
  424.     if (pw->paint.pattern != None)
  425.         XSetTile(XtDisplay(w), pw->paint.fgc, pw->paint.pattern);
  426.     if (pw->paint.fontInfo != NULL && pw->paint.fontInfo->fid != None)
  427.         XSetFont(XtDisplay(w), pw->paint.fgc, pw->paint.fontInfo->fid);
  428.  
  429.     /*
  430.     **  Then the line GC
  431.      */
  432.     XSetFillStyle(XtDisplay(w), pw->paint.sgc, pw->paint.lineFillRule);
  433.     XSetLineAttributes(XtDisplay(w), pw->paint.sgc,
  434.                pw->paint.lineWidth, LineSolid,
  435.                CapRound, JoinMiter);
  436.     if (pw->paint.linePattern != None)
  437.         XSetTile(XtDisplay(w), pw->paint.sgc, pw->paint.linePattern);
  438.     } else if (pw->paint.paint != None) {
  439.     pw->paint.sgc = pp->paint.sgc;
  440.     pw->paint.fgc = pp->paint.fgc;
  441.     }
  442.     /*
  443.     **    Parent realized after children, odd..
  444.      */
  445.     if (pp == None && pw->paint.paintChildrenSize != 0)
  446.     for (i = 0; i < pw->paint.paintChildrenSize; i++) {
  447.         PaintWidget tp = (PaintWidget) pw->paint.paintChildren[i];
  448.         tp->paint.sgc = pw->paint.sgc;
  449.         tp->paint.fgc = pw->paint.fgc;
  450.         tp->paint.igc = pw->paint.igc;
  451.         tp->paint.xgc = pw->paint.xgc;
  452.         tp->paint.tgc = pw->paint.tgc;
  453.     }
  454.     /*
  455.     **    Create the backing undo buffers
  456.      */
  457.     for (cur = pw->paint.head; cur && (cur->pixmap == None); cur = cur->next)
  458.     cur->pixmap = XCreatePixmap(XtDisplay(w), XtWindow(w),
  459.                    pw->paint.drawWidth, pw->paint.drawHeight,
  460.                     depth);
  461.  
  462.     /*
  463.     **    If this paint widget is the child of another paint
  464.     **     widget then either create our own unique information
  465.     **     or just use the information from our parent.
  466.      */
  467.     if (pw->paint.paint == None) {
  468.     pw->paint.current = pw->paint.head->pixmap;
  469.  
  470.     if (pw->paint.sourcePixmap != None)
  471.         pwSetPixmap(pw, pw->paint.sourcePixmap, FALSE);
  472.     else
  473.         XFillRectangle(XtDisplay(w), pw->paint.current,
  474.                pw->paint.igc, 0, 0,
  475.                pw->paint.drawWidth, pw->paint.drawHeight);
  476.     } else
  477.     PwAddChild(pw->paint.paint, w);
  478.  
  479.     XGetWindowAttributes(XtDisplay(w), XtWindow(w), &wattr);
  480.     pw->paint.visual = wattr.visual;
  481.  
  482.     if (pw->paint.cursor != None)
  483.     XDefineCursor(XtDisplay(pw), XtWindow(pw), pw->paint.cursor);
  484. }
  485.  
  486. static void
  487. DestroyProc(Widget w)
  488. {
  489.     PaintWidget pw = (PaintWidget) w;
  490.     UndoStack *cur, *nxt;
  491.  
  492.     if (pw->paint.mgc != None)
  493.     XFreeGC(XtDisplay(pw), pw->paint.mgc);
  494.     if (pw->paint.gc != None)
  495.     XtReleaseGC(w, pw->paint.gc);
  496.  
  497.     if (pw->paint.region.source != None)
  498.     XFreePixmap(XtDisplay(pw), pw->paint.region.source);
  499.     if (pw->paint.region.mask != None)
  500.     XFreePixmap(XtDisplay(pw), pw->paint.region.mask);
  501.     if (pw->paint.region.notMask != None)
  502.     XFreePixmap(XtDisplay(pw), pw->paint.region.notMask);
  503.     if (pw->paint.region.sourceImg != NULL)
  504.     XDestroyImage(pw->paint.region.sourceImg);
  505.     if (pw->paint.region.maskImg != NULL)
  506.     XDestroyImage(pw->paint.region.maskImg);
  507.     if (pw->paint.region.notMaskImg != NULL)
  508.     XDestroyImage(pw->paint.region.notMaskImg);
  509.  
  510.     if (pw->paint.paint != None)
  511.     return;
  512.  
  513.     /*    WARNING: the rest of this callback doesn't execute for children */
  514.  
  515.     if (pw->paint.filename != NULL)
  516.     free(pw->paint.filename);
  517.     if (pw->paint.menuwidgets != NULL)
  518.     free(pw->paint.menuwidgets);
  519.  
  520.     if (pw->paint.tgc != None)
  521.     XFreeGC(XtDisplay(pw), pw->paint.tgc);
  522.     if (pw->paint.xgc != None)
  523.     XFreeGC(XtDisplay(pw), pw->paint.xgc);
  524.     if (pw->paint.igc != None)
  525.     XFreeGC(XtDisplay(pw), pw->paint.igc);
  526.     if (pw->paint.fgc != None)
  527.     XFreeGC(XtDisplay(pw), pw->paint.fgc);
  528.     if (pw->paint.sgc != None)
  529.     XFreeGC(XtDisplay(pw), pw->paint.sgc);
  530.  
  531.     cur = pw->paint.head;
  532.     do {
  533.     nxt = cur->next;
  534.     if (cur->pixmap != None)
  535.         XFreePixmap(XtDisplay(pw), cur->pixmap);
  536.     XtFree((XtPointer) cur);
  537.     cur = nxt;
  538.     }
  539.     while (cur != pw->paint.head);
  540.  
  541.     if (pw->paint.image != NULL) {
  542.     XDestroyRegion(pw->paint.imageRegion);
  543.     XDestroyImage(pw->paint.image);
  544.     }
  545.     if (pw->paint.paintChildren != NULL)
  546.     XtFree((XtPointer) pw->paint.paintChildren);
  547. }
  548.  
  549. static void
  550. ResizeProc(Widget w)
  551. {
  552.  
  553. }
  554.  
  555. static void
  556. drawVisibleGrid(PaintWidget pw, Widget w, Boolean flag,
  557.         int zoom, int sx, int sy, int ex, int ey)
  558. {
  559.     static GC tgc = None;
  560.     GC gc;
  561.     Display *dpy = XtDisplay(w);
  562.     Window win = XtWindow(w);
  563.     int i;
  564.  
  565.     if (zoom <= 1)
  566.     return;
  567.  
  568.     if (flag) {
  569.     if (tgc == None) {
  570.         XGCValues values;
  571.  
  572.         values.foreground = BlackPixelOfScreen(XtScreen(w));
  573.         tgc = XtGetGC(w, GCForeground, &values);
  574.     }
  575.     gc = tgc;
  576.     } else {
  577.     /*
  578.     **  Turning off visible grid, and we need to clear
  579.     **    to no space between pixels...
  580.      */
  581.     if (zoom <= ZOOM_THRESH) {
  582.         XClearArea(dpy, win, sx, sy, ex - sx, ey - sy, True);
  583.         return;
  584.     }
  585.     gc = pw->paint.igc;
  586.     }
  587.  
  588.     for (i = sx; i < ex; i += zoom)
  589.     XDrawLine(dpy, win, gc, i, sy, i, ey);
  590.     for (i = sy; i < ey; i += zoom)
  591.     XDrawLine(dpy, win, gc, sx, i, ex, i);
  592. }
  593.  
  594. /*
  595. **  Update the zoomed region as specified by rect.
  596. **    rect is in screen coordinates.
  597. **
  598. **  There are two drawers, the first draws using rectangles
  599. **   the second draws using XImages.
  600. **
  601.  */
  602.  
  603. static void
  604. zoomDrawRects(PaintWidget pw, Widget w, GC gc, XImage * xim, XImage * mask,
  605.           Boolean isExpose, int xstart, int ystart, int zoom,
  606.           XRectangle * rect)
  607. {
  608.     static Boolean *flags = NULL;
  609.     static int flagsSize = 0;
  610.     Display *dpy = XtDisplay(w);
  611.     Window win = XtWindow(w);
  612.     int width = rect->width;
  613.     int count = rect->width * rect->height;
  614.     XRectangle rects[256];
  615.     int index, i;
  616.  
  617.     if (flagsSize < count) {
  618.     int allocSize = (count + 4) * sizeof(Boolean);
  619.     if (flags == NULL)
  620.         flags = (Boolean *) XtMalloc(allocSize);
  621.     else
  622.         flags = (Boolean *) XtRealloc((XtPointer) flags, allocSize);
  623.     flagsSize = count;
  624.     }
  625.     memset(flags, 0, flagsSize * sizeof(Boolean));
  626.     if (mask != NULL) {
  627.     int x, y;
  628.  
  629.     i = 0;
  630.     for (y = rect->y; y < rect->height + rect->y; y++) {
  631.         for (x = rect->x; x < rect->width + rect->x; x++, i++) {
  632.         if (!XGetPixel(mask, x, y))
  633.             flags[i] = True;
  634.         }
  635.     }
  636.     }
  637.     for (i = 0; i < XtNumber(rects) && i < count; i++)
  638.     if (zoom > ZOOM_THRESH)
  639.         rects[i].width = rects[i].height = zoom - 1;
  640.     else
  641.         rects[i].width = rects[i].height = zoom;
  642.  
  643.     for (index = 0; index != count; index++) {
  644.     if (!flags[index]) {
  645.         int xindex = index % width + rect->x;
  646.         int yindex = index / width + rect->y;
  647.         int xindexEnd = rect->x + rect->width;
  648.         Pixel p = xxGetPixel(xim, xindex, yindex);
  649.         int xpos = (index % width + xstart) * zoom;
  650.         int ypos = (index / width + ystart) * zoom;
  651.         int pos, flag;
  652.  
  653.         flag = (isExpose && p == w->core.background_pixel);
  654.  
  655.         XSetForeground(dpy, gc, p);
  656.         for (pos = index, i = 0; pos != count;
  657.          pos++, xindex++, xpos += zoom) {
  658.         if (xindex == xindexEnd) {
  659.             xindex = rect->x;
  660.             xpos = xstart * zoom;
  661.             yindex++;
  662.             ypos += zoom;
  663.         }
  664.         if (flags[pos] || xxGetPixel(xim, xindex, yindex) != p)
  665.             continue;
  666.         flags[pos] = True;
  667.  
  668.         if (flag)
  669.             continue;
  670.  
  671.         rects[i].x = xpos;
  672.         rects[i].y = ypos;
  673.         i++;
  674.  
  675.         if (i == XtNumber(rects)) {
  676.             XFillRectangles(dpy, win, gc, rects, i);
  677.             i = 0;
  678.         }
  679.         }
  680.         if (i > 0)
  681.         XFillRectangles(dpy, win, gc, rects, i);
  682.     }
  683.     }
  684. }
  685.  
  686. static void
  687. zoomDrawImage(PaintWidget pw, Widget w, GC gc, XImage * xim, XImage * mask,
  688.           Boolean isExpose, int xstart, int ystart, int zoom,
  689.           XRectangle * rect)
  690. {
  691.     Display *dpy = XtDisplay(w);
  692.     int width = rect->width;
  693.     int height = rect->height;
  694.     XImage *dst;
  695.     XImage *dstMsk = NULL;
  696.     int x, y, x1, y1, dx, dy;
  697.     int numDraw = zoom - ((zoom > ZOOM_THRESH) ? 1 : 0);
  698.     int endX = rect->x + rect->width;
  699.     int endY = rect->y + rect->height;
  700.  
  701.     dst = XCreateImage(dpy, pw->paint.visual, xim->depth, xim->format,
  702.                0, NULL, width * zoom, height * zoom, 32, 0);
  703.     dst->data = (char *) XtMalloc(height * zoom * dst->bytes_per_line);
  704.     if (mask != NULL) {
  705.     dstMsk = XCreateImage(dpy, pw->paint.visual,
  706.                   mask->depth, mask->format,
  707.                   0, NULL, width * zoom, height * zoom, 8, 0);
  708.     dstMsk->data = (char *) XtMalloc(height * zoom * dstMsk->bytes_per_line);
  709.     memset(dstMsk->data, 0, height * zoom * dstMsk->bytes_per_line);
  710.     }
  711.     if (mask == NULL) {
  712.     for (dy = 0, y = rect->y; y < endY; y++, dy += zoom) {
  713.         for (dx = 0, x = rect->x; x < endX; x++, dx += zoom) {
  714.         Pixel p;
  715.  
  716.         p = xxGetPixel(xim, x, y);
  717.  
  718.         for (y1 = 0; y1 < numDraw; y1++) {
  719.             for (x1 = 0; x1 < numDraw; x1++) {
  720.             xxPutPixel(dst, dx + x1, dy + y1, p);
  721.             }
  722.             if (numDraw != zoom)
  723.             xxPutPixel(dst, dx + x1, dy + y1,
  724.                    w->core.background_pixel);
  725.         }
  726.         if (numDraw != zoom)
  727.             for (x1 = 0; x1 < zoom; x1++)
  728.             xxPutPixel(dst, dx + x1, dy + y1,
  729.                    w->core.background_pixel);
  730.         }
  731.     }
  732.     } else {
  733.     for (dy = 0, y = rect->y; y < endY; y++, dy += zoom) {
  734.         for (dx = 0, x = rect->x; x < endX; x++, dx += zoom) {
  735.         Pixel p;
  736.  
  737.         if (!xxGetPixel(mask, x, y))
  738.             continue;
  739.  
  740.         p = xxGetPixel(xim, x, y);
  741.  
  742.         for (y1 = 0; y1 < numDraw; y1++) {
  743.             for (x1 = 0; x1 < numDraw; x1++) {
  744.             xxPutPixel(dst, dx + x1, dy + y1, p);
  745.             xxPutPixel(dstMsk, dx + x1, dy + y1, True);
  746.             }
  747.         }
  748.         }
  749.     }
  750.     }
  751.  
  752.     if (mask != NULL) {
  753.     Pixmap pix = XCreatePixmap(XtDisplay(w), XtWindow(w),
  754.                    width * zoom, height * zoom, 1);
  755.  
  756.     XPutImage(XtDisplay(w), pix, pw->paint.mgc, dstMsk,
  757.           0, 0, 0, 0, width * zoom, height * zoom);
  758.  
  759.     XSetClipMask(XtDisplay(w), gc, pix);
  760.     XSetClipOrigin(XtDisplay(w), gc, xstart * zoom, ystart * zoom);
  761.     XPutImage(XtDisplay(w), XtWindow(w), gc, dst, 0, 0,
  762.           xstart * zoom, ystart * zoom,
  763.           width * zoom, height * zoom);
  764.     XSetClipMask(XtDisplay(w), gc, None);
  765.  
  766.     XFreePixmap(XtDisplay(w), pix);
  767.     } else {
  768.     XPutImage(XtDisplay(w), XtWindow(w), gc, dst, 0, 0,
  769.           xstart * zoom, ystart * zoom,
  770.           width * zoom, height * zoom);
  771.     }
  772.  
  773.     XDestroyImage(dst);
  774.     if (dstMsk != NULL)
  775.     XDestroyImage(dstMsk);
  776. }
  777.  
  778. static void
  779. zoomUpdate(PaintWidget pw, Boolean isExpose, XRectangle * rect)
  780. {
  781.     int zoom = GET_ZOOM(pw);
  782.     int sx, sy, w, h, zsx, zsy;
  783.     XImage *xim;
  784.     XRectangle *isec, *tmp;
  785.     XRectangle real, grab;
  786.  
  787.     if ((isec = RectIntersect(rect, GetRectangle(pw))) == NULL)
  788.     return;
  789.  
  790.     zsx = sx = isec->x / zoom;
  791.     zsy = sy = isec->y / zoom;
  792.     w = (isec->width + (isec->x % zoom) + zoom - 1) / zoom;
  793.     h = (isec->height + (isec->y % zoom) + zoom - 1) / zoom;
  794.  
  795.     grab.x = sx + pw->paint.zoomX;
  796.     grab.y = sy + pw->paint.zoomY;
  797.     grab.width = w;
  798.     grab.height = h;
  799.     real.x = 0;
  800.     real.y = 0;
  801.     real.width = pw->paint.drawWidth;
  802.     real.height = pw->paint.drawHeight;
  803.  
  804.     if ((tmp = RectIntersect(&grab, &real)) == NULL)
  805.     return;
  806.  
  807.     xim = PwGetImage((Widget) pw, tmp);
  808.  
  809.     real.x = tmp->x;
  810.     real.y = tmp->y;
  811.     real.width = tmp->width;
  812.     real.height = tmp->height;
  813.  
  814.     _PwZoomDraw(pw, (Widget) pw, pw->paint.tgc, xim, NULL,
  815.         isExpose, sx, sy, zoom, &real);
  816. }
  817.  
  818. /*
  819. **  pw    = parent paint widget
  820. **  w    = widget who's window will be updated
  821. **  gc    = gc to use (read/written)
  822. **  src = source XImage to use
  823. **  mask = mask XImage to use
  824. **  flag = is this an expose event, so we don't have to
  825. **       update pixels == window background
  826. **  sx,sy = start x, y for window drawing (non-zoomed)
  827. **  zoom = zoom value to apply
  828. **  rect = region of the input ximages to use to draw
  829. **       a start x,y with the specified width,height
  830.  */
  831. void
  832. _PwZoomDraw(PaintWidget pw, Widget w, GC gc, XImage * src, XImage * mask,
  833.         Boolean flag, int sx, int sy, int zoom, XRectangle * rect)
  834. {
  835.     if (rect->width * rect->height < 1024 + 256)
  836.     zoomDrawRects(pw, w, gc, src, mask, flag, sx, sy, zoom, rect);
  837.     else
  838.     zoomDrawImage(pw, w, gc, src, mask, flag, sx, sy, zoom, rect);
  839.  
  840.     if (pw->paint.grid) {
  841.     int xstart, xend, ystart, yend;
  842.  
  843.     xstart = sx * zoom - 1;
  844.     ystart = sy * zoom - 1;
  845.     xend = xstart + rect->width * zoom + zoom - 1;
  846.     yend = ystart + rect->height * zoom + zoom - 1;
  847.  
  848.     drawVisibleGrid(pw, w, True, zoom, xstart, ystart, xend, yend);
  849.     }
  850. }
  851.  
  852.  
  853. void
  854. PwUpdateDrawable(Widget w, Drawable draw, XRectangle * rect)
  855. {
  856.     PaintWidget pw = (PaintWidget) w;
  857.     XRectangle all;
  858.     Pixmap pix = GET_PIXMAP(pw);
  859.  
  860.     if (rect == NULL || rect->width == 0 || rect->height == 0) {
  861.     rect = &all;
  862.     all.x = all.y = 0;
  863.     all.width = pw->core.width;
  864.     all.height = pw->core.height;
  865.     }
  866.     XCopyArea(XtDisplay(w), pix, draw, pw->paint.gc,
  867.           rect->x + pw->paint.zoomX,
  868.           rect->y + pw->paint.zoomY,
  869.           rect->width, rect->height,
  870.           rect->x, rect->y);
  871. }
  872.  
  873. static void
  874. realExposeProc(PaintWidget pw, XExposeEvent * event, Boolean flag)
  875. {
  876.     int x, y, width, height;
  877.     XRectangle rect;
  878.  
  879.     if (!XtIsRealized(((Widget) pw)))
  880.     return;
  881.  
  882.     /*
  883.     **    Clean up the event, since I do simulate them
  884.      */
  885.     x = event->x;
  886.     y = event->y;
  887.     width = event->width;
  888.     height = event->height;
  889.  
  890.     if (x < 0) {
  891.     width += x;
  892.     x = 0;
  893.     }
  894.     if (y < 0) {
  895.     height += y;
  896.     y = 0;
  897.     }
  898.     if (width < 0 || height < 0)
  899.     return;
  900.     if (x > pw->core.width || y > pw->core.height)
  901.     return;
  902.     if (x + width > pw->core.width)
  903.     width = pw->core.width - x;
  904.     if (y + height > pw->core.height)
  905.     height = pw->core.height - y;
  906.  
  907.     rect.x = x;
  908.     rect.y = y;
  909.     rect.width = width;
  910.     rect.height = height;
  911.  
  912.     if (GET_ZOOM(pw) <= 1)
  913.     PwUpdateDrawable((Widget) pw, XtWindow((Widget) pw), &rect);
  914.     else
  915.     zoomUpdate(pw, flag, &rect);
  916. }
  917.  
  918. static void
  919. ExposeProc(Widget w, XExposeEvent * event)
  920. {
  921.     realExposeProc((PaintWidget) w, event, True);
  922. }
  923.  
  924. static void
  925. resizePixmap(PaintWidget w, Pixmap * pixmap)
  926. {
  927.     Pixmap n;
  928.  
  929.     if (pixmap == NULL || *pixmap == None)
  930.     return;
  931.  
  932.     n = XCreatePixmap(XtDisplay(w), XtWindow(w),
  933.               w->paint.drawWidth, w->paint.drawHeight,
  934.               w->core.depth);
  935.     XFillRectangle(XtDisplay(w), n,
  936.            w->paint.igc, 0, 0,
  937.            w->paint.drawWidth, w->paint.drawHeight);
  938.     XCopyArea(XtDisplay(w), *pixmap, n,
  939.           w->paint.gc, 0, 0,
  940.           w->paint.drawWidth, w->paint.drawHeight, 0, 0);
  941.     XFreePixmap(XtDisplay(w), *pixmap);
  942.     *pixmap = n;
  943. }
  944.  
  945. static Boolean
  946. SetValuesProc(Widget curArg, Widget request,
  947.           Widget newArg)
  948. {
  949.     PaintWidget cur = (PaintWidget) curArg;
  950.     PaintWidget new = (PaintWidget) newArg;
  951.     int ret = False;
  952.     int sizeChanged = False;
  953.     int i;
  954.  
  955.     if (cur->paint.sourcePixmap != new->paint.sourcePixmap)
  956.     pwSetPixmap(new, new->paint.sourcePixmap, True);
  957.  
  958.     if (cur->paint.compress != new->paint.compress)
  959.     new->core.widget_class->core_class.compress_motion = new->paint.compress;
  960.  
  961.     if (!XtIsRealized((Widget) new))
  962.     return ret;
  963.  
  964.     if (cur->paint.fillRule != new->paint.fillRule)
  965.     XSetFillStyle(XtDisplay(new), new->paint.fgc, new->paint.fillRule);
  966.     if (cur->paint.foreground != new->paint.foreground)
  967.     XSetForeground(XtDisplay(new), new->paint.fgc, new->paint.foreground);
  968.     if (cur->paint.pattern != new->paint.pattern)
  969.     XSetTile(XtDisplay(new), new->paint.fgc, new->paint.pattern);
  970.  
  971.     if (cur->paint.lineFillRule != new->paint.lineFillRule)
  972.     XSetFillStyle(XtDisplay(new), new->paint.sgc, new->paint.lineFillRule);
  973.     if (cur->paint.lineForeground != new->paint.lineForeground)
  974.     XSetForeground(XtDisplay(new),
  975.                new->paint.sgc, new->paint.lineForeground);
  976.     if (cur->paint.linePattern != new->paint.linePattern)
  977.     XSetTile(XtDisplay(new), new->paint.sgc, new->paint.linePattern);
  978.  
  979.     if (cur->paint.lineWidth != new->paint.lineWidth) {
  980.     XSetLineAttributes(XtDisplay(new), new->paint.fgc,
  981.                new->paint.lineWidth, LineSolid,
  982.                CapRound, JoinMiter);
  983.     XSetLineAttributes(XtDisplay(new), new->paint.sgc,
  984.                new->paint.lineWidth, LineSolid,
  985.                CapRound, JoinMiter);
  986.     }
  987.     if (cur->paint.fontInfo->fid != new->paint.fontInfo->fid) {
  988.     XSetFont(XtDisplay(new), new->paint.fgc,
  989.          new->paint.fontInfo->fid);
  990.     }
  991.     if (cur->paint.drawWidth != new->paint.drawWidth ||
  992.     cur->paint.drawHeight != new->paint.drawHeight) {
  993.     UndoStack *cur;
  994.     int gotit = 0;
  995.  
  996.     /*
  997.     **  Resize the undo buffers
  998.      */
  999.     if (new->paint.paint == None) {
  1000.         cur = new->paint.head;
  1001.         do {
  1002.         if (cur->pixmap == new->paint.current)
  1003.             gotit = 1;
  1004.         resizePixmap(new, &cur->pixmap);
  1005.         if (gotit) {
  1006.             new->paint.current = cur->pixmap;
  1007.             gotit = 0;
  1008.         }
  1009.         } while ((cur = cur->next) != new->paint.head);
  1010.         new->paint.undobot = new->paint.undoitems = 0;
  1011.         new->paint.redobot = new->paint.redoitems = 0;
  1012.     }
  1013.     /*
  1014.     **  Destroy the XImage that is cached
  1015.      */
  1016.     if (new->paint.image != NULL) {
  1017.         XDestroyImage(new->paint.image);
  1018.         XDestroyRegion(new->paint.imageRegion);
  1019.         new->paint.image = NULL;
  1020.     }
  1021.     if (XtMakeResizeRequest((Widget) new,
  1022.                 new->paint.drawWidth * new->paint.zoom,
  1023.                 new->paint.drawHeight * new->paint.zoom,
  1024.                 NULL, NULL) == XtGeometryDone) {
  1025.         ret = True;
  1026.         sizeChanged = True;
  1027.     }
  1028.     for (i = 0; i < new->paint.paintChildrenSize; i++) {
  1029.         XtVaSetValues(new->paint.paintChildren[i],
  1030.               XtNdrawWidth, new->paint.drawWidth,
  1031.               XtNdrawHeight, new->paint.drawHeight,
  1032.               NULL);
  1033.     }
  1034.     }
  1035.     if (cur->paint.zoom != new->paint.zoom) {
  1036.     ret = True;
  1037.  
  1038.     XtMakeResizeRequest((Widget) new,
  1039.                 new->paint.drawWidth * new->paint.zoom,
  1040.                 new->paint.drawHeight * new->paint.zoom,
  1041.                 NULL, NULL);
  1042.     sizeChanged = True;
  1043.     }
  1044.     if (cur->paint.zoomX != new->paint.zoomX ||
  1045.     cur->paint.zoomY != new->paint.zoomY) {
  1046.     XExposeEvent event;
  1047.  
  1048.     event.x = 0;
  1049.     event.y = 0;
  1050.     event.width = new->core.width;
  1051.     event.height = new->core.height;
  1052.  
  1053.     realExposeProc(new, &event, False);
  1054.     pwRegionZoomPosChanged(new);
  1055.     }
  1056.     if (cur->paint.grid != new->paint.grid) {
  1057.     XRectangle *rect = GetRectangle(new);
  1058.  
  1059.     rect->x -= rect->x % new->paint.zoom + 1;
  1060.     rect->y -= rect->y % new->paint.zoom + 1;
  1061.  
  1062.     drawVisibleGrid(new, (Widget) new,
  1063.             new->paint.grid, GET_ZOOM(new),
  1064.             rect->x, rect->y,
  1065.             rect->x + rect->width, rect->y + rect->height);
  1066.  
  1067.     for (i = 0; i < new->paint.paintChildrenSize; i++) {
  1068.         XtVaSetValues(new->paint.paintChildren[i],
  1069.               XtNgrid, new->paint.grid,
  1070.               NULL);
  1071.     }
  1072.     }
  1073.     if (cur->core.background_pixel != new->core.background_pixel)
  1074.     XSetForeground(XtDisplay(new), new->paint.igc,
  1075.                new->core.background_pixel);
  1076.  
  1077.     if (cur->paint.cursor != new->paint.cursor)
  1078.     XDefineCursor(XtDisplay(new), XtWindow(new), new->paint.cursor);
  1079.  
  1080.     /*
  1081.      * Number of undo levels changed.
  1082.      * Free old undo buffers and undo/redo stacks,
  1083.      * and allocate new ones. Catch: we need to preserve
  1084.      * the currently used undo buffer, otherwise we'll
  1085.      * lose everything on the canvas.
  1086.      */
  1087.     if (cur->paint.undoSize != new->paint.undoSize) {
  1088.     UndoStack * this, * nxt, * first;
  1089.     
  1090.     this = cur->paint.head;
  1091.     do {
  1092.         nxt = this->next;
  1093.         if (this->pixmap != cur->paint.current)
  1094.         XFreePixmap(XtDisplay(new), this->pixmap);
  1095.         free(this);
  1096.         this = nxt;
  1097.     } while (this != cur->paint.head);
  1098.     new->paint.head = NULL;
  1099.     for (i = 0; i <= new->paint.undoSize; i++) {
  1100.         this = undoBuffer(new);
  1101.         if (i == 0) {
  1102.         first = this;
  1103.         this->pixmap = cur->paint.current;
  1104.         } else {
  1105.         this->pixmap = XCreatePixmap(XtDisplay(new), XtWindow(new),
  1106.                          new->paint.drawWidth,
  1107.                          new->paint.drawHeight,
  1108.                      DefaultDepthOfScreen(XtScreen(new)));
  1109.         XFillRectangle(XtDisplay(new), this->pixmap,
  1110.                    new->paint.igc, 0, 0,
  1111.                    new->paint.drawWidth, new->paint.drawHeight);
  1112.         }
  1113.     }
  1114.     first->next = new->paint.head;
  1115.     new->paint.current = cur->paint.current;
  1116.     new->paint.undo = new->paint.head;
  1117.     free(cur->paint.undostack);
  1118.     free(cur->paint.redostack);
  1119.     UndoInitialize(new, new->paint.undoSize);
  1120.     }    
  1121.  
  1122.     if (sizeChanged)
  1123.     XtCallCallbackList((Widget) new, new->paint.sizecalls, NULL);
  1124.  
  1125.     return ret;
  1126. }
  1127.  
  1128. static void
  1129. GetValuesHook(Widget w, ArgList args, Cardinal * nargs)
  1130. {
  1131.     PaintWidget pw = (PaintWidget) w;
  1132.     PaintWidget pp = (PaintWidget) pw->paint.paint;
  1133.     Arg a;
  1134.     int i;
  1135.  
  1136.     if (pp == None)
  1137.     return;
  1138.  
  1139.     for (i = 0; i < *nargs; i++) {
  1140.     char *nm = args[i].name;
  1141.  
  1142.     if (strcmp(nm, XtNlineWidth) == 0)
  1143.         XtSetArg(a, XtNlineWidth, args[i].value);
  1144.     else if (strcmp(nm, XtNlineFillRule) == 0)
  1145.         XtSetArg(a, XtNlineFillRule, args[i].value);
  1146.     else if (strcmp(nm, XtNfillRule) == 0)
  1147.         XtSetArg(a, XtNfillRule, args[i].value);
  1148.     else if (strcmp(nm, XtNdrawWidth) == 0)
  1149.         XtSetArg(a, XtNdrawWidth, args[i].value);
  1150.     else if (strcmp(nm, XtNdrawHeight) == 0)
  1151.         XtSetArg(a, XtNdrawHeight, args[i].value);
  1152.     else
  1153.         continue;
  1154.     XtGetValues((Widget) pp, &a, 1);
  1155.     }
  1156. }
  1157.  
  1158. static int
  1159. QueryGeometryProc(Widget w, XtWidgetGeometry * proposed,
  1160.           XtWidgetGeometry * reply)
  1161. {
  1162.  
  1163. /*
  1164. **  Use the fact that the return values are ordered by "importance"
  1165.  */
  1166. #define SETRET(ret,x)    ret = (x > ret) ? x : ret
  1167.     PaintWidget pw = (PaintWidget) w;
  1168.     int width = pw->paint.drawWidth * pw->paint.zoom;
  1169.     int height = pw->paint.drawHeight * pw->paint.zoom;
  1170.  
  1171.     reply->request_mode = CWWidth | CWHeight;
  1172.     reply->width = width;
  1173.     reply->height = height;
  1174.  
  1175.     if (((proposed->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight))
  1176.     && (proposed->width == reply->width)
  1177.     && (proposed->height == reply->height))
  1178.     return XtGeometryNo;
  1179.     else
  1180.     return XtGeometryAlmost;
  1181. }
  1182.  
  1183. /*
  1184.  * Convenience routine (with caching) to get an XImage of an area
  1185.  */
  1186. XImage *
  1187. PwGetImage(Widget w, XRectangle * rect)
  1188. {
  1189.     PaintWidget pw = (PaintWidget) w;
  1190.     Pixmap pix = GET_PIXMAP(pw);
  1191.     Region r;
  1192.     XRectangle clean;
  1193.  
  1194.     if (pw->paint.paint != None)
  1195.     pw = (PaintWidget) pw->paint.paint;
  1196.  
  1197.  
  1198.     if (rect != NULL) {
  1199.     if (rect->x < 0) {
  1200.         clean.x = 0;
  1201.         clean.width = rect->width + rect->x;
  1202.     } else {
  1203.         clean.x = rect->x;
  1204.         clean.width = rect->width;
  1205.     }
  1206.     if (rect->y < 0) {
  1207.         clean.y = 0;
  1208.         clean.height = rect->height + rect->y;
  1209.     } else {
  1210.         clean.y = rect->y;
  1211.         clean.height = rect->height;
  1212.     }
  1213.     if (clean.width > pw->paint.drawWidth)
  1214.         clean.width = pw->paint.drawWidth;
  1215.     if (clean.height > pw->paint.drawHeight)
  1216.         clean.height = pw->paint.drawHeight;
  1217.     } else {
  1218.     clean.x = 0;
  1219.     clean.y = 0;
  1220.     clean.width = pw->paint.drawWidth;
  1221.     clean.height = pw->paint.drawHeight;
  1222.     }
  1223.  
  1224.     if (pw->paint.image == NULL) {
  1225.     pw->paint.image = XCreateImage(XtDisplay(w), pw->paint.visual,
  1226.                        pw->core.depth, ZPixmap, 0, NULL,
  1227.                        pw->paint.drawWidth, pw->paint.drawHeight,
  1228.                        32, 0);
  1229.     pw->paint.image->data = (char *)
  1230.         XtMalloc(pw->paint.drawHeight * pw->paint.image->bytes_per_line);
  1231.     pw->paint.imageRegion = XCreateRegion();
  1232.     pw->paint.invalidateRegion = False;
  1233.     }
  1234.     if (pw->paint.invalidateRegion) {
  1235.     XDestroyRegion(pw->paint.imageRegion);
  1236.     pw->paint.imageRegion = XCreateRegion();
  1237.     pw->paint.invalidateRegion = False;
  1238.     }
  1239.     if (XRectInRegion(pw->paint.imageRegion, clean.x, clean.y,
  1240.               clean.width, clean.height) == RectangleIn)
  1241.     return pw->paint.image;
  1242.  
  1243.     r = XCreateRegion();
  1244.     XUnionRectWithRegion(&clean, r, r);
  1245.     XSubtractRegion(r, pw->paint.imageRegion, r);
  1246.  
  1247.     XClipBox(r, &clean);
  1248.  
  1249.     /*
  1250.     **    Since this is "caching" grow the image slightly over the
  1251.     **      requested size.
  1252.      */
  1253.     if ((clean.x -= 8) < 0)
  1254.     clean.x = 0;
  1255.     if ((clean.y -= 8) < 0)
  1256.     clean.y = 0;
  1257.     if ((clean.width += 16) > pw->paint.drawWidth - clean.x)
  1258.     clean.width = pw->paint.drawWidth - clean.x;
  1259.     if ((clean.height += 16) > pw->paint.drawHeight - clean.y)
  1260.     clean.height = pw->paint.drawHeight - clean.y;
  1261.  
  1262.     XGetSubImage(XtDisplay(pw), pix, clean.x, clean.y,
  1263.          clean.width, clean.height, AllPlanes, ZPixmap,
  1264.          pw->paint.image, clean.x, clean.y);
  1265.     XUnionRectWithRegion(&clean, pw->paint.imageRegion,
  1266.              pw->paint.imageRegion);
  1267.  
  1268.     XDestroyRegion(r);
  1269.  
  1270.     return pw->paint.image;
  1271. }
  1272.  
  1273. void
  1274. PwGetPixmap(Widget w, Pixmap * pix, int *width, int *height)
  1275. {
  1276.     PaintWidget pw = (PaintWidget) w;
  1277.     *pix = None;
  1278.  
  1279.     if (pw->paint.paint != None) {
  1280.     PwGetPixmap((Widget) pw->paint.paint, pix, width, height);
  1281.     return;
  1282.     }
  1283.     if (width != NULL)
  1284.     *width = pw->paint.drawWidth;
  1285.     if (height != NULL)
  1286.     *height = pw->paint.drawHeight;
  1287.  
  1288.     *pix = XCreatePixmap(XtDisplay(w), XtWindow(w),
  1289.              pw->paint.drawWidth, pw->paint.drawHeight,
  1290.              pw->core.depth);
  1291.     PwUpdateDrawable(w, *pix, NULL);
  1292. }
  1293.  
  1294. /*  Get the pixmap id of the current region image */
  1295. Pixmap
  1296. PwGetRawPixmap(Widget w)
  1297. {
  1298.     PaintWidget pw = (PaintWidget) w;
  1299.  
  1300.     if (pw->paint.paint != None)
  1301.     return PwGetRawPixmap((Widget) pw->paint.paint);
  1302.  
  1303.     return GET_PIXMAP(pw);
  1304. }
  1305.  
  1306. static void
  1307. pwSetPixmap(PaintWidget w, Pixmap pix, int flag)
  1308. {
  1309.     Window root;
  1310.     int x, y;
  1311.     unsigned int width, height, bw, depth;
  1312.  
  1313.     XGetGeometry(XtDisplay(w), pix,
  1314.          &root, &x, &y, &width, &height, &bw, &depth);
  1315.  
  1316.     XCopyArea(XtDisplay(w), pix, GET_PIXMAP(w),
  1317.           w->paint.gc, 0, 0, width, height, 0, 0);
  1318. }
  1319.  
  1320. static void
  1321. fatCallback(Widget parent, XtPointer w, XtPointer rectArg)
  1322. {
  1323.     XRectangle *rect = (XRectangle *) rectArg;
  1324.     PaintWidget pw = (PaintWidget) w;
  1325.     XExposeEvent event;
  1326.     int zoom = GET_ZOOM(pw);
  1327.  
  1328.     /*
  1329.     **    Make this look like an expose event on the fatbits region
  1330.      */
  1331.     event.x = (rect->x - pw->paint.zoomX) * zoom;
  1332.     event.y = (rect->y - pw->paint.zoomY) * zoom;
  1333.     event.width = rect->width * zoom;
  1334.     event.height = rect->height * zoom;
  1335.  
  1336.     realExposeProc(pw, &event, False);
  1337. }
  1338.  
  1339. /*
  1340.  * If rect is NULL, use undo box size.
  1341.  */
  1342. void
  1343. PwUpdate(Widget w, XRectangle * rect, Boolean force)
  1344. {
  1345.     PaintWidget pw = (PaintWidget) w;
  1346.     PaintWidget parent = (PaintWidget) pw->paint.paint;
  1347.     PaintWidget usePW = (parent == None) ? pw : parent;
  1348.     XRectangle all;
  1349.  
  1350.     if (rect == NULL) {
  1351.     if (pw->paint.undo == NULL) {
  1352.         all.x = 0;
  1353.         all.y = 0;
  1354.         all.width = pw->core.width;
  1355.         all.height = pw->core.height;
  1356.         rect = &all;
  1357.     } else {
  1358.         rect = &pw->paint.undo->box;
  1359.     }
  1360.     } else {
  1361.     all.x = rect->x - pw->paint.lineWidth;
  1362.     all.y = rect->y - pw->paint.lineWidth;
  1363.     all.width = rect->width + pw->paint.lineWidth * 2;
  1364.     all.height = rect->height + pw->paint.lineWidth * 2;
  1365.     rect = &all;
  1366.     }
  1367.  
  1368.     /*
  1369.     **    If we have a caching image
  1370.      */
  1371.     if (usePW->paint.image != NULL && !usePW->paint.invalidateRegion)
  1372.     usePW->paint.invalidateRegion = True;
  1373.  
  1374.     XtCallCallbackList((Widget) usePW, usePW->paint.fatcalls,
  1375.                (XtPointer) rect);
  1376.  
  1377.     if (force || (pw->paint.zoom > 1) || parent != None)
  1378.     fatCallback((Widget) usePW, (XtPointer) usePW, (XtPointer) rect);
  1379. }
  1380.  
  1381. /*
  1382. **  Update the current visual buffer with the contents
  1383. **   of the undo area, thus a pseudo-real time undo.
  1384. **   (it's not undo at all)
  1385. **  Called from fontOp.c.
  1386.  */
  1387. void
  1388. PwUpdateFromLast(Widget w, XRectangle * rect)
  1389. {
  1390.     Pixmap pix;
  1391.     PaintWidget pw = (PaintWidget) w;
  1392.     Pixmap draw = GET_PIXMAP(pw);
  1393.  
  1394.     if (pw->paint.paint != None)
  1395.     pw = (PaintWidget) pw->paint.paint;
  1396.  
  1397.     pix = pw->paint.undo->pixmap;
  1398.  
  1399.     XCopyArea(XtDisplay(w), pix, draw, pw->paint.gc,
  1400.           rect->x, rect->y, rect->width, rect->height,
  1401.           rect->x, rect->y);
  1402.     PwUpdate(w, rect, True);
  1403. }
  1404.  
  1405. /*
  1406. **  Bogus XXX
  1407.  */
  1408. XRectangle *
  1409. PwScaleRectangle(Widget w, XRectangle * src)
  1410. {
  1411.     return src;
  1412. }
  1413.  
  1414. void
  1415. PwPutPixmap(Widget w, Pixmap pix)
  1416. {
  1417.     PaintWidget pw = (PaintWidget) w;
  1418.     GC gc = pw->paint.gc;
  1419.     Pixmap dst;
  1420.     Window root;
  1421.     int x, y;
  1422.     unsigned int width, height, bw, depth;
  1423.     XRectangle rect;
  1424.  
  1425.     XGetGeometry(XtDisplay(w), pix, &root, &x, &y, &width, &height, &bw, &depth);
  1426.     rect.x = 0;
  1427.     rect.y = 0;
  1428.     rect.width = width;
  1429.     rect.height = height;
  1430.     dst = PwUndoStart(w, &rect);
  1431.     XCopyArea(XtDisplay(pw), pix, dst, gc, 0, 0,
  1432.           width, height, 0, 0);
  1433.     PwUpdate(w, &rect, True);
  1434. }
  1435.  
  1436. static void
  1437. removeChild(Widget child, Widget w)
  1438. {
  1439.     PaintWidget pw = (PaintWidget) w;
  1440.     int i;
  1441.  
  1442.     for (i = 0; i < pw->paint.paintChildrenSize; i++)
  1443.     if (pw->paint.paintChildren[i] == child)
  1444.         break;
  1445.     for (i++; i < pw->paint.paintChildrenSize; i++)
  1446.     pw->paint.paintChildren[i - 1] = pw->paint.paintChildren[i];
  1447.  
  1448.     pw->paint.paintChildrenSize--;
  1449.  
  1450.     XtRemoveCallback((Widget) w, XtNfatBack, fatCallback, (XtPointer) child);
  1451. }
  1452.  
  1453. void
  1454. PwAddChild(Widget w, Widget child)
  1455. {
  1456.     PaintWidget pw = (PaintWidget) w;
  1457.  
  1458.     if (pw->paint.paintChildren == NULL)
  1459.     pw->paint.paintChildren = (Widget *)
  1460.         XtMalloc(sizeof(Widget) * (pw->paint.paintChildrenSize + 2));
  1461.     else
  1462.     pw->paint.paintChildren = (Widget *)
  1463.         XtRealloc((XtPointer) pw->paint.paintChildren,
  1464.               sizeof(Widget) * (pw->paint.paintChildrenSize + 2));
  1465.     pw->paint.paintChildren[pw->paint.paintChildrenSize++] = child;
  1466.     XtAddCallback(child, XtNdestroyCallback, (XtCallbackProc) removeChild,
  1467.           (XtPointer) w);
  1468.     XtAddCallback(w, XtNfatBack, fatCallback, (XtPointer) child);
  1469. }
  1470.