home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xpaint-247 / misc.c < prev    next >
C/C++ Source or Header  |  1997-01-03  |  16KB  |  487 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
  3. /* | Copyright 1995, 1996 Torsten Martinsen (bullestock@dk-online.dk)  | */
  4. /* |                                                                   | */
  5. /* | Permission to use, copy, modify, and to distribute this software  | */
  6. /* | and its documentation for any purpose is hereby granted without   | */
  7. /* | fee, provided that the above copyright notice appear in all       | */
  8. /* | copies and that both that copyright notice and this permission    | */
  9. /* | notice appear in supporting documentation.  There is no           | */
  10. /* | representations about the suitability of this software for        | */
  11. /* | any purpose.  this software is provided "as is" without express   | */
  12. /* | or implied warranty.                                              | */
  13. /* |                                                                   | */
  14. /* +-------------------------------------------------------------------+ */
  15.  
  16. /* $Id: misc.c,v 1.11 1996/05/09 07:11:53 torsten Exp $ */
  17.  
  18. #include <X11/Intrinsic.h>
  19. #include <X11/StringDefs.h>
  20. #include <X11/cursorfont.h>
  21. #ifndef VMS
  22. #include <X11/Xaw/Label.h>
  23. #else
  24. #include <X11Xaw/Label.h>
  25. #endif
  26. #include <ctype.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <math.h>
  30.  
  31. #include "bitmaps/background.xbm"
  32.  
  33. #ifndef XtNcursor
  34. #define XtNcursor     "cursor"
  35. #endif
  36.  
  37. #include "xpaint.h"
  38. #include "misc.h"
  39. #include "PaintP.h"
  40. #include "palette.h"
  41. #include "protocol.h"
  42.  
  43.  
  44. Widget
  45. GetToplevel(Widget w)
  46. {
  47.     Widget p = w;
  48.  
  49.     while (w != None) {
  50.     p = w;
  51.     w = XtParent(w);
  52.     }
  53.     return p;
  54. }
  55.  
  56. Widget
  57. GetShell(Widget w)
  58. {
  59.     while (!XtIsShell(w))
  60.     w = XtParent(w);
  61.     return w;
  62. }
  63.  
  64. void 
  65. SetIBeamCursor(Widget w)
  66. {
  67.     XtVaSetValues(w, XtVaTypedArg,
  68.           XtNcursor, XtRString, "xterm", sizeof(Cursor), NULL);
  69. }
  70.  
  71. void 
  72. SetCrossHairCursor(Widget w)
  73. {
  74.     XtVaSetValues(w, XtVaTypedArg,
  75.         XtNcursor, XtRString, "crosshair", sizeof(Cursor), NULL);
  76. }
  77. void 
  78. SetPencilCursor(Widget w)
  79. {
  80.     XtVaSetValues(w, XtVaTypedArg,
  81.           XtNcursor, XtRString, "pencil", sizeof(Cursor), NULL);
  82. }
  83.  
  84.  
  85. /*
  86. **  Some useful XRectangle computation code.
  87.  */
  88. XRectangle *
  89. RectUnion(XRectangle * a, XRectangle * b)
  90. {
  91.     static XRectangle out;
  92.     int sx, ex, sy, ey;
  93.  
  94.     sx = MIN(a->x, b->x);
  95.     sy = MIN(a->y, b->y);
  96.     ex = MAX(a->x + a->width, b->x + b->width);
  97.     ey = MAX(a->y + a->height, b->y + b->height);
  98.  
  99.     XYtoRECT(sx, sy, ex, ey, &out);
  100.  
  101.     return &out;
  102. }
  103.  
  104. XRectangle *
  105. RectIntersect(XRectangle * a, XRectangle * b)
  106. {
  107.     static XRectangle out;
  108.     int w, h;
  109.  
  110.     if (a == NULL || b == NULL)
  111.     return NULL;
  112.  
  113.     out.x = MAX(a->x, b->x);
  114.     out.y = MAX(a->y, b->y);
  115.     w = MIN(a->x + a->width, b->x + b->width) - out.x;
  116.     h = MIN(a->y + a->height, b->y + b->height) - out.y;
  117.  
  118.     if (w <= 0 || h <= 0)
  119.     return NULL;
  120.  
  121.     out.width = w;
  122.     out.height = h;
  123.  
  124.     return &out;
  125. }
  126.  
  127. /*
  128. **
  129.  */
  130. void 
  131. GetPixmapWHD(Display * dpy, Drawable d, int *wth, int *hth, int *dth)
  132. {
  133.     Window root;
  134.     int x, y;
  135.     unsigned int width, height, bw, depth;
  136.  
  137.     XGetGeometry(dpy, d, &root, &x, &y, &width, &height, &bw, &depth);
  138.  
  139.     if (wth != NULL)
  140.     *wth = width;
  141.     if (hth != NULL)
  142.     *hth = height;
  143.     if (dth != NULL)
  144.     *dth = depth;
  145. }
  146.  
  147. /*
  148. **  Two useful functions to "cache" both a tiled background
  149. **    and a Xor gc
  150.  */
  151. typedef struct bgList_s {
  152.     int depth;
  153.     Pixmap pixmap;
  154.     struct bgList_s *next;
  155. } BackgroundList;
  156.  
  157. static BackgroundList *bgList = NULL;
  158.  
  159. Pixmap
  160. GetBackgroundPixmap(Widget w)
  161. {
  162.     Widget p, n;
  163.     Display *dpy = XtDisplay(w);
  164.     int depth;
  165.     Pixmap pix;
  166.     Pixel fg, bg;
  167.     BackgroundList *cur;
  168.     Widget tw;
  169.  
  170.     for (n = XtParent(p = w); !XtIsShell(n); n = XtParent(p = n));
  171.  
  172.     XtVaGetValues(p, XtNdepth, &depth, NULL);
  173.  
  174.     for (cur = bgList; bgList != NULL; bgList = bgList->next)
  175.     if (cur->depth == depth)
  176.         return cur->pixmap;
  177.  
  178.     tw = XtVaCreateWidget("junkWidget", labelWidgetClass, w,
  179.               XtNwidth, 1,
  180.               XtNheight, 1,
  181.               NULL);
  182.     XtVaGetValues(tw, XtNforeground, &fg,
  183.           XtNbackground, &bg,
  184.           NULL);
  185.  
  186.     XtDestroyWidget(tw);
  187.  
  188.     pix = XCreatePixmapFromBitmapData(dpy, DefaultRootWindow(dpy),
  189.                       (char *) background_bits,
  190.                       background_width, background_height,
  191.                       bg, fg, depth);
  192.  
  193.     cur = XtNew(BackgroundList);
  194.     cur->next = bgList;
  195.     bgList = cur;
  196.     cur->depth = depth;
  197.     cur->pixmap = pix;
  198.     return pix;
  199. }
  200.  
  201. typedef struct gcList_s {
  202.     Widget widget;
  203.     int depth;
  204.     GC gc;
  205.     struct gcList_s *next;
  206. } GCXList;
  207.  
  208. static GCXList *gcList = NULL;
  209.  
  210. GC
  211. GetGCX(Widget w)
  212. {
  213.     Widget n = GetShell(w);
  214.     int depth;
  215.     GCXList *cur;
  216.     XGCValues values;
  217.  
  218.     XtVaGetValues(n, XtNdepth, &depth, NULL);
  219.  
  220.     for (cur = gcList; gcList != NULL; gcList = gcList->next)
  221.     if (cur->depth == depth)
  222.         return cur->gc;
  223.  
  224.     values.function = GXxor;
  225.     values.foreground = ~0;
  226.  
  227.     cur = XtNew(GCXList);
  228.     cur->next = gcList;
  229.     gcList = cur;
  230.     cur->depth = depth;
  231.     cur->gc = XtGetGC(n, GCFunction | GCForeground, &values);
  232.     return cur->gc;
  233. }
  234.  
  235. /*
  236. **  Argv parsing routines
  237.  */
  238.  
  239. static char *
  240. nextArg(char *str, char **start)
  241. {
  242.     char *cp;
  243.     int flg;
  244.  
  245.     while (isspace(*str))
  246.     str++;
  247.     if (start != NULL)
  248.     *start = str;
  249.     if (*str == '\0')
  250.     return NULL;
  251.     if (*str == '\'' || *str == '"') {
  252.     char delim = *str;
  253.     if (start != NULL)
  254.         (*start)++;
  255.     cp = ++str;
  256.     while (*str != '\0' && *str != delim) {
  257.         if (*str == '\\') {
  258.         if (*++str == '\0')
  259.             continue;
  260.         }
  261.         *cp++ = *str++;
  262.     }
  263.     *cp = '\0';
  264.     } else {
  265.     while (!isspace(*str) && *str != '\0')
  266.         str++;
  267.     }
  268.  
  269.     flg = (*str != '\0');
  270.     *str = '\0';
  271.     return str + (flg ? 1 : 0);
  272. }
  273.  
  274. void 
  275. StrToArgv(char *str, int *argc, char **argv)
  276. {
  277.     int t;
  278.     char *cp;
  279.  
  280.     if (argc == NULL)
  281.     argc = &t;
  282.  
  283.     *argc = 0;
  284.     for (cp = str; cp != NULL; (*argc)++)
  285.     cp = nextArg(cp, argv == NULL ? NULL : &argv[*argc]);
  286.  
  287.     if (argv != NULL)
  288.     argv[--(*argc)] = NULL;
  289. }
  290.  
  291. /*
  292. **  Create a XImage
  293.  */
  294. XImage *
  295. NewXImage(Display * dpy, Visual * visual, int depth, int width, int height)
  296. {
  297.     XImage *xim;
  298.     int pad;
  299.  
  300.     if (depth > 16)
  301.     pad = 32;
  302.     else if (depth > 8)
  303.     pad = 16;
  304.     else
  305.     pad = 8;
  306.  
  307.     xim = XCreateImage(dpy, visual, depth, ZPixmap, 0, NULL,
  308.                width, height, pad, 0);
  309.  
  310.     if (xim == NULL)
  311.     return NULL;
  312.  
  313.     xim->data = (char *) XtMalloc(xim->bytes_per_line * height);
  314.  
  315.     if (xim->data == NULL) {
  316.     XDestroyImage(xim);
  317.     xim = NULL;
  318.     }
  319.     return xim;
  320. }
  321.  
  322. /*
  323.  * Return a Gaussian (aka normal) random variable.
  324.  *
  325.  * Adapted from ppmforge.c, which is part of PBMPLUS.
  326.  * The algorithm comes from:
  327.  * 'The Science Of Fractal Images'. Peitgen, H.-O., and Saupe, D. eds.
  328.  * Springer Verlag, New York, 1988.
  329.  */
  330. double 
  331. gauss(void)
  332. {
  333.     int i;
  334.     double sum = 0.0;
  335.  
  336.     for (i = 0; i < 4; i++)
  337.     sum += RANDOMI() & 0x7FFF;
  338.  
  339.     return sum * 5.28596089837e-5 - 3.46410161514;
  340. }
  341.  
  342. /*
  343.  * Return a Gaussian (aka normal) random variable, multiplied by 'range'
  344.  * and clamped to [-range, range]. Note: integer return.
  345.  */
  346. int 
  347. gaussclamp(int range)
  348. {
  349.     /* The '2.5' is a fudge factor; this value IMHO gives the best result */
  350.     int g = gauss() * range / 2.5;
  351.  
  352.     if (g < -range)
  353.     g = -range;
  354.     else if (g > range)
  355.     g = range;
  356.     return g;
  357. }
  358.  
  359. void *
  360. xmalloc(size_t n)
  361. {
  362.     void *p;
  363.  
  364.     if ((p = malloc(n)) != NULL)
  365.     return p;
  366.     fprintf(stderr, "Out of memory\n");
  367.     exit(1);
  368. }
  369.  
  370. /*
  371.  * Remove same-coloured borders from image.
  372.  * Portions of this code taken from pnmcrop.c, which is part of the PBMPLUS
  373.  * package, and carries the following copyright:
  374.  */
  375. /*
  376. ** Copyright (C) 1988 by Jef Poskanzer.
  377. **
  378. ** Permission to use, copy, modify, and distribute this software and its
  379. ** documentation for any purpose and without fee is hereby granted, provided
  380. ** that the above copyright notice appear in all copies and that both that
  381. ** copyright notice and this permission notice appear in supporting
  382. ** documentation.  This software is provided "as is" without express or
  383. ** implied warranty.
  384.  */
  385. void 
  386. AutoCrop(Widget paint)
  387. {
  388.     PaintWidget pw = (PaintWidget) paint;
  389.     int i;
  390.     int x, y, width, height, top, bottom, left, right;
  391.     Pixmap pix;
  392.     Pixel corner[4], bg;
  393.     XImage *xim;
  394.     Colormap cmap;
  395.     Palette *palette;
  396.     Display *dpy = XtDisplay(pw);
  397.     XRectangle rect;
  398.  
  399.  
  400.     StateSetBusy(True);
  401.     PwRegionFinish(paint, True);
  402.     width = pw->paint.drawWidth;
  403.     height = pw->paint.drawHeight;
  404.  
  405.     /*
  406.      * First try to guess the border colour.
  407.      */
  408.     XtVaGetValues(paint, XtNcolormap, &cmap, NULL);
  409.     palette = PaletteFind(paint, cmap);
  410.  
  411.     /* Find the RGB values for the four corners. */
  412.     pix = XCreatePixmap(dpy, XtWindow(pw), width, height, pw->core.depth);
  413.     xim = NewXImage(dpy, NULL, pw->core.depth, width, height);
  414.     XGetSubImage(dpy, GET_PIXMAP(pw), 0, 0, width, height,
  415.          AllPlanes, ZPixmap, xim, 0, 0);
  416.     for (y = 0, i = 0; y < height; y += height - 1)
  417.     for (x = 0; x < width; x += width - 1)
  418.         corner[i++] = XGetPixel(xim, x, y);
  419.  
  420.     if ((corner[0] == corner[1]) || (corner[0] == corner[2]) ||
  421.     (corner[0] == corner[3]))
  422.     bg = corner[0];
  423.     else if ((corner[1] == corner[2]) || (corner[1] == corner[3]))
  424.     bg = corner[1];
  425.     else if (corner[2] == corner[3])
  426.     bg = corner[2];
  427.     else {
  428.     XDestroyImage(xim);
  429.     StateSetBusy(False);
  430.     return;            /* No two corners have the same colour */
  431.     }
  432.  
  433.     /* Find first non-background line. */
  434.     for (top = 0; top < height; top++)
  435.     for (x = 0; x < width; x++)
  436.         if (XGetPixel(xim, x, top) != bg)
  437.         goto gottop;
  438.   gottop:
  439.  
  440.     /* Find last non-background line. */
  441.     for (bottom = height - 1; bottom >= top; bottom--)
  442.     for (x = 0; x < width; x++)
  443.         if (XGetPixel(xim, x, bottom) != bg)
  444.         goto gotbottom;
  445.   gotbottom:
  446.  
  447.     /* Find first non-background column. */
  448.     left = width - 1;
  449.     for (y = top; y <= bottom; y++)
  450.     for (x = 0; x < left; x++)
  451.         if (XGetPixel(xim, x, y) != bg) {
  452.         left = x;
  453.         break;
  454.         }
  455.     /* Find last non-background column. */
  456.     right = left + 1;
  457.     for (y = top; y <= bottom; y++)
  458.     for (x = width - 1; x > right; x--)
  459.         if (XGetPixel(xim, x, y) != bg) {
  460.         right = x;
  461.         break;
  462.         }
  463.     XDestroyImage(xim);
  464.  
  465.     rect.x = left;
  466.     rect.y = top;
  467.     rect.width = right - left + 1;
  468.     rect.height = bottom - top + 1;
  469.  
  470.     if (((left == 0) && (right == width - 1) &&
  471.      (top == 0) && (bottom == height - 1))
  472.     || (rect.width < 1) || (rect.height < 1)) {
  473.     StateSetBusy(False);
  474.     return;
  475.     }
  476.     PwRegionSet(paint, &rect, None, None);
  477.     PwRegionGet(paint, &pix, None);
  478.     PwRegionFinish(paint, True);
  479.  
  480.     XtVaSetValues((Widget) paint, XtNpixmap, pix,
  481.          XtNdrawWidth, rect.width, XtNdrawHeight, rect.height, NULL);
  482.  
  483.     pw->paint.dirty = True;
  484.     PwUpdateDrawable((Widget) paint, XtWindow(paint), NULL);
  485.     StateSetBusy(False);
  486. }