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

  1.  
  2. /* +-------------------------------------------------------------------+ */
  3. /* | Copyright 1993, David Koblas (koblas@netcom.com)                  | */
  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: protocol.c,v 1.4 1996/05/24 07:33:03 torsten Exp $ */
  17.  
  18. #include <X11/Intrinsic.h>
  19. #include <X11/StringDefs.h>
  20. #include <X11/Xatom.h>
  21. #include <X11/cursorfont.h>
  22. #include <sys/time.h>
  23. #include <stdio.h>
  24.  
  25. #include "xpaint.h"
  26. #include "misc.h"
  27. #include "protocol.h"
  28.  
  29. #ifdef VMS
  30. #include "unix_time.h"
  31. #endif
  32.  
  33. typedef struct li_s {
  34.     /*
  35.     **  Destroy request info
  36.      */
  37.     void *data;
  38.     DestroyCallbackFunc func;
  39.  
  40.     /*
  41.     **  Info for watch cursor
  42.      */
  43.     int watchCount, computingCount;
  44.     Widget shell, parent;
  45.     Window win;
  46.     Display *dpy;
  47.     struct li_s *next;
  48. } LocalInfo;
  49.  
  50. #define    DO_MAP(l)    ((l)->watchCount + (l)->computingCount > 0)
  51.  
  52. #include "bitmaps/wait1.xbm"
  53. #include "bitmaps/wait2.xbm"
  54. #include "bitmaps/wait3.xbm"
  55. #include "bitmaps/wait4.xbm"
  56.  
  57. static Atom delwin = None, protocols = None;
  58. static LocalInfo *head = NULL;
  59.  
  60. static int currentCursor = 0;
  61. static Cursor watchCursor = None;
  62.  
  63. static struct {
  64.     Cursor cursor;
  65.     int width, height;
  66.     unsigned char *bits;
  67. } cursorInfo[] =
  68.  
  69. {
  70.     {
  71.     None, wait1_width, wait1_height, wait1_bits
  72.     }
  73.     ,
  74.     {
  75.     None, wait2_width, wait2_height, wait2_bits
  76.     }
  77.     ,
  78.     {
  79.     None, wait3_width, wait3_height, wait3_bits
  80.     }
  81.     ,
  82.     {
  83.     None, wait4_width, wait4_height, wait4_bits
  84.     }
  85.     ,
  86. };
  87.  
  88. static void 
  89. initCursors(Widget w)
  90. {
  91.     static int inited = False;
  92.     Display *dpy = XtDisplay(w);
  93.     Screen *screen = XtScreen(w);
  94.     GC gc = None;
  95.     Pixmap pix, mask;
  96.     int i, width, height;
  97.     XImage *src, *msk;
  98.     int x, y;
  99.     XColor xcols[2];
  100.  
  101.     if (inited)
  102.     return;
  103.     inited = True;
  104.  
  105.     xcols[0].pixel = BlackPixelOfScreen(screen);
  106.     xcols[1].pixel = WhitePixelOfScreen(screen);
  107.  
  108.     XQueryColors(dpy, DefaultColormapOfScreen(screen), xcols, XtNumber(xcols));
  109.  
  110.     for (i = 0; i < XtNumber(cursorInfo); i++) {
  111.     width = cursorInfo[i].width;
  112.     height = cursorInfo[i].height;
  113.     pix = XCreatePixmapFromBitmapData(dpy, RootWindowOfScreen(screen),
  114.          (char *) cursorInfo[i].bits, width, height, True, False, 1);
  115.     src = XGetImage(dpy, pix, 0, 0, width, height, AllPlanes, ZPixmap);
  116.     msk = NewXImage(dpy, NULL, 1, width, height);
  117.     for (y = 0; y < height; y++) {
  118.         for (x = 0; x < width; x++) {
  119.         Boolean flg = (Boolean) XGetPixel(src, x, y);
  120.  
  121.         if (!flg && x > 0)
  122.             flg = XGetPixel(src, x - 1, y);
  123.         if (!flg && x < width - 1)
  124.             flg = XGetPixel(src, x + 1, y);
  125.         if (!flg && y > 0)
  126.             flg = XGetPixel(src, x, y - 1);
  127.         if (!flg && y < height - 1)
  128.             flg = XGetPixel(src, x, y + 1);
  129.         XPutPixel(msk, x, y, flg);
  130.         }
  131.     }
  132.  
  133.     mask = XCreatePixmap(dpy, pix, width, height, 1);
  134.     if (gc == None)
  135.         gc = XCreateGC(dpy, mask, 0, 0);
  136.     XPutImage(dpy, mask, gc, msk, 0, 0, 0, 0, width, height);
  137.  
  138.     XDestroyImage(src);
  139.     XDestroyImage(msk);
  140.  
  141.     cursorInfo[i].cursor = XCreatePixmapCursor(dpy, pix, mask,
  142.                 &xcols[0], &xcols[1], width / 2, height / 2);
  143.     XFreePixmap(dpy, pix);
  144.     XFreePixmap(dpy, mask);
  145.     }
  146.     if (gc != None)
  147.     XFreeGC(dpy, gc);
  148. }
  149.  
  150. static void 
  151. destroyCallback(Widget w, XtPointer data, XtPointer junk)
  152. {
  153.     LocalInfo *l = (LocalInfo *) data;
  154.     LocalInfo *cur, **pp;
  155.  
  156.     for (cur = *(pp = &head); cur != NULL && cur != l; cur = *(pp = &cur->next));
  157.  
  158.     if (cur == NULL)
  159.     return;
  160.  
  161.     *pp = cur->next;
  162.  
  163.     XtFree((XtPointer) data);
  164. }
  165.  
  166. static void 
  167. handler(Widget w, XtPointer lArg, XEvent * eventArg, Boolean * junk)
  168. {
  169.     XClientMessageEvent *event = (XClientMessageEvent *) eventArg;
  170.     LocalInfo *l = (LocalInfo *) lArg;
  171.     if (event->type != ClientMessage)
  172.     return;
  173.  
  174.     if (event->message_type == protocols && event->data.l[0] == delwin)
  175.     l->func(w, l->data, eventArg);
  176. }
  177.  
  178. static void 
  179. add(Widget w, LocalInfo * l)
  180. {
  181.     unsigned long valuemask;
  182.     XSetWindowAttributes attributes;
  183.     /*
  184.     **  Set up the shell destroy info
  185.      */
  186.     XtAddRawEventHandler(w, 0, True, handler, (XtPointer) l);
  187.     XChangeProperty(XtDisplay(w), XtWindow(w), protocols,
  188.             XA_ATOM, 32, PropModeReplace,
  189.             (unsigned char *) &delwin, 1);
  190.  
  191.     /* 
  192.     **  Now set up watch cursor information
  193.     **
  194.     **  Ignore device events while the busy cursor is displayed.
  195.      */
  196.     valuemask = CWDontPropagate | CWCursor;
  197.     attributes.do_not_propagate_mask = (KeyPressMask | KeyReleaseMask |
  198.         ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
  199.     if (watchCursor == None)
  200.     watchCursor = XCreateFontCursor(XtDisplay(w), XC_watch);
  201.     attributes.cursor = watchCursor;
  202.  
  203.     /*
  204.     ** The window will be as big as the display screen, and clipped by
  205.     ** its own parent window, so we never have to worry about resizing
  206.      */
  207.     l->win = XCreateWindow(XtDisplay(w), XtWindow(w), 0, 0,
  208.          WidthOfScreen(XtScreen(w)), HeightOfScreen(XtScreen(w)),
  209.                (unsigned int) 0, 0, InputOnly,
  210.                CopyFromParent, valuemask, &attributes);
  211.  
  212.     if (DO_MAP(l))
  213.     XMapRaised(l->dpy, l->win);
  214. }
  215.  
  216.  
  217. static void 
  218. realize(Widget w, XtPointer ldataArg, XEvent * event, Boolean * junk)
  219. {
  220.     if (event->type == MapNotify) {
  221.     XtRemoveEventHandler(w, StructureNotifyMask, False,
  222.                  realize, ldataArg);
  223.     add(w, (LocalInfo *) ldataArg);
  224.     }
  225. }
  226.  
  227. void 
  228. AddDestroyCallback(Widget w, DestroyCallbackFunc func, void *data)
  229. {
  230.     LocalInfo *l;
  231.  
  232.     if (delwin == None)
  233.     delwin = XInternAtom(XtDisplay(w), "WM_DELETE_WINDOW", FALSE);
  234.     if (protocols == None)
  235.     protocols = XInternAtom(XtDisplay(w), "WM_PROTOCOLS", FALSE);
  236.  
  237.     initCursors(w);
  238.  
  239.     if (delwin == None || protocols == None) {
  240.     printf("Error in XInternAtom\n");
  241.     exit(1);
  242.     }
  243.  
  244.     l = XtNew(LocalInfo);
  245.     l->data = data;
  246.     l->func = func;
  247.     l->win = None;
  248.     l->dpy = XtDisplay(w);
  249.     l->watchCount = 0;
  250.     l->computingCount = 0;
  251.     l->shell = w;
  252.     l->parent = None;
  253.  
  254.     if (!XtIsRealized(w))
  255.     XtAddEventHandler(w, StructureNotifyMask, False, realize, (XtPointer) l);
  256.     else
  257.     add(w, l);
  258.  
  259.     XtAddCallback(w, XtNdestroyCallback, destroyCallback, (XtPointer) l);
  260.  
  261.     l->next = head;
  262.     head = l;
  263. }
  264.  
  265. static Boolean
  266. setBusy(LocalInfo * cur, Boolean isWatch, Boolean flag)
  267. {
  268.     Boolean doFlush = False;
  269.  
  270.     if (isWatch) {
  271.     if (flag) {
  272.         cur->watchCount++;
  273.     } else {
  274.         if (cur->watchCount == 0)
  275.         return False;
  276.         cur->watchCount--;
  277.     }
  278.     } else {
  279.     if (flag) {
  280.         cur->computingCount++;
  281.     } else {
  282.         if (cur->computingCount == 0)
  283.         return False;
  284.         cur->computingCount--;
  285.     }
  286.     }
  287.  
  288.     if (cur->win == None)
  289.     return False;
  290.  
  291.     if (cur->watchCount == 0 && cur->computingCount == 0) {
  292.     XUnmapWindow(cur->dpy, cur->win);
  293.     return False;
  294.     }
  295.     if (cur->watchCount == 1) {
  296.     if (isWatch) {
  297.         XMapRaised(cur->dpy, cur->win);
  298.         XDefineCursor(cur->dpy, cur->win, watchCursor);
  299.         doFlush = True;
  300.     }
  301.     } else if (cur->computingCount == 1) {
  302.     if (!isWatch) {
  303.         XMapRaised(cur->dpy, cur->win);
  304.         XDefineCursor(cur->dpy, cur->win, cursorInfo[currentCursor].cursor);
  305.         doFlush = True;
  306.     }
  307.     }
  308.     return doFlush;
  309. }
  310.  
  311. /*
  312.  * Turn watch cursor on (True) or off (False).
  313.  */
  314. void 
  315. StateSetBusyWatch(Boolean flag)
  316. {
  317.     LocalInfo *cur;
  318.     Boolean doFlush = False;
  319.  
  320.     for (cur = head; cur != NULL; cur = cur->next)
  321.     doFlush |= setBusy(cur, True, flag);
  322.  
  323.     if (doFlush)
  324.     XFlush(head->dpy);
  325. }
  326.  
  327. /*
  328.  * Turn busy cursor on (True) or off (False).
  329.  */
  330. void 
  331. StateSetBusy(Boolean flag)
  332. {
  333.     LocalInfo *cur;
  334.     Boolean doFlush = False;
  335.  
  336.     for (cur = head; cur != NULL; cur = cur->next)
  337.     doFlush |= setBusy(cur, False, flag);
  338.  
  339.     if (doFlush)
  340.     XFlush(head->dpy);
  341. }
  342.  
  343. void 
  344. StateShellBusy(Widget w, Boolean flag)
  345. {
  346.     LocalInfo *cur;
  347.     Boolean doFlush = False;
  348.  
  349.     if (w == None)
  350.     return;
  351.  
  352.     while (!XtIsShell(w))
  353.     w = XtParent(w);
  354.  
  355.     for (cur = head; cur != NULL; cur = cur->next) {
  356.     if (cur->shell == w) {
  357.         doFlush |= setBusy(cur, True, flag);
  358.     } else if (cur->parent == w) {
  359.         StateShellBusy(cur->shell, flag);
  360.     }
  361.     }
  362.     if (doFlush)
  363.     XFlush(head->dpy);
  364. }
  365.  
  366. void 
  367. StateAddParent(Widget w, Widget parent)
  368. {
  369.     LocalInfo *cur;
  370.  
  371.     if (w == None || parent == None)
  372.     return;
  373.  
  374.     while (!XtIsShell(parent))
  375.     parent = XtParent(parent);
  376.     while (!XtIsShell(w))
  377.     w = XtParent(w);
  378.  
  379.     for (cur = head; cur != NULL && cur->shell != w; cur = cur->next);
  380.     if (cur == NULL)
  381.     return;
  382.  
  383.     cur->parent = parent;
  384. }
  385.  
  386. void 
  387. StateTimeStep(void)
  388. {
  389.     static Boolean inited = False;
  390.     static struct timeval lastTime;
  391.     struct timeval nowTime;
  392.     Boolean done = False, need = False;
  393.     Cursor c;
  394.     LocalInfo *cur;
  395.  
  396.     for (cur = head; cur != NULL; cur = cur->next)
  397.     if (cur->watchCount == 0 && cur->computingCount != 0 && cur->win != None)
  398.         need = True;
  399.  
  400.     if (!need)
  401.     return;
  402.  
  403.     gettimeofday(&nowTime, NULL);
  404.     if (inited) {
  405.     long ds, dus;
  406.  
  407.     dus = nowTime.tv_usec - lastTime.tv_usec;
  408.     ds = nowTime.tv_sec - lastTime.tv_sec;
  409.     if (dus < 0) {
  410.         ds--;
  411.         dus += 1000000;
  412.     }
  413.     if (ds == 0 && dus < 200000)
  414.         return;
  415.     } else {
  416.     inited = True;
  417.     }
  418.     lastTime = nowTime;
  419.  
  420.  
  421.     if (++currentCursor == XtNumber(cursorInfo))
  422.     currentCursor = 0;
  423.  
  424.     c = cursorInfo[currentCursor].cursor;
  425.  
  426.     for (cur = head; cur != NULL; cur = cur->next) {
  427.     if (cur->watchCount == 0 && cur->computingCount != 0 && cur->win != None) {
  428.         XDefineCursor(cur->dpy, cur->win, c);
  429.         done = True;
  430.     }
  431.     }
  432.  
  433.     if (done)
  434.     XFlush(head->dpy);
  435. }