Logo Search packages:      
Sourcecode: acfax version File versions  Download package

Canvas.c

/*
 * $Header: /home/orchestra5/davy/stuff/misc/xsat/RCS/Canvas.c,v 1.1 92/04/10 14:08:02 davy Exp $
 *
 * Copyright 1992 by David A. Curry
 * Adapted for use with ACfax by Andreas Czechanowski
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting documentation.  The
 * author makes no representations about the suitability of this software for
 * any purpose.  It is provided "as is" without express or implied warranty.
 *
 * Code for the Canvas widget.  Based in part on the Template widget from
 * the X11R5 distribution; I also looked quite a bit at the code from the
 * "xproof" program to figure out how to set things up.
 *
 * David A. Curry
 * Purdue University
 * Engineering Computer Network
 * 1285 Electrical Engineering Building
 * West Lafayette, IN 47907
 * davy@ecn.purdue.edu
 *
 * $Log:    Canvas.c,v $
 * Revision 1.1  92/04/10  14:08:02  davy
 * Initial revision
 * 
 */
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/cursorfont.h>
#include <X11/Xlib.h>
#include <stdio.h>

#include "CanvasP.h"

static void Destroy();
static void Realize();
static void Redisplay();
static void Resize();
static XtGeometryResult QueryGeometry();
static Boolean    SetValues();
static XtGeometryResult Geometry_manager();
static void Initialize();
static void Notify();
void  canvasIdle();
void  canvasBusy();
void  canvasClearPicture();
void  canvasUpdateArea();

/*
 * Canvas widget translations
 */
static char defaultTranslations[] =
    "<Btn1Down>:  notify()";
/*
 * Canvas widget actions
 */
static XtActionsRec actionsList[] = {
  {"notify",      Notify}
};
/*
 * Canvas widget resources.
 */
/* offset to a canvas-element in the widget-structure */
#define offset(field) XtOffsetOf(CanvasRec,canvas.field)
/* offset to a core-element in the widget-stucture */
#define goffset(field) XtOffsetOf(CanvasRec,core.field)
static XtResource resources[] = {
      { XtNbackground,  XtCBackground,    XtRPixel,   sizeof(Pixel),
            goffset(background_pixel),    XtRString,  "white" },
      { XtNidleCursor,  XtCCursor,  XtRCursor,  sizeof(Cursor),
            offset(idle_cursor),          XtRString,  "left_ptr" },
      { XtNbusyCursor,  XtCCursor,  XtRCursor,  sizeof(Cursor),
            offset(busy_cursor),          XtRString,  "watch" },
      { XtNcallback,          XtCCallback,       XtRCallback,     sizeof(XtPointer),
            offset(callbacks),            XtRCallback,      (XtPointer)NULL},
/*
      { XtNfont,        XtCFont,    XtRFontStruct,    sizeof(XFontStruct *),
            offset(font),                 XtRString,  XtDefaultFont },
*/
};
#undef offset
#undef goffset

CanvasClassRec canvasClassRec = {
  { /* core fields */
    /* superclass       */    (WidgetClass) &compositeClassRec,
    /* class_name       */    "Canvas",
    /* widget_size            */    sizeof(CanvasRec),
    /* class_initialize       */    NULL,
    /* class_part_initialize  */    NULL,
    /* class_inited           */    FALSE,
    /* initialize       */    Initialize,
    /* initialize_hook        */    NULL,
    /* realize                */    Realize,
    /* actions                */    actionsList,
    /* num_actions            */    XtNumber(actionsList),
    /* resources        */    resources,
    /* num_resources          */    XtNumber(resources),
    /* xrm_class        */    NULLQUARK,
    /* compress_motion        */    TRUE,
    /* compress_exposure      */    TRUE,
    /* compress_enterleave    */    TRUE,
    /* visible_interest       */    FALSE,
    /* destroy                */    Destroy,
    /* resize                 */    Resize,
    /* expose                 */    Redisplay,
    /* set_values       */    SetValues,
    /* set_values_hook        */    NULL,
    /* set_values_almost      */    XtInheritSetValuesAlmost,
    /* get_values_hook        */    NULL,
    /* accept_focus           */    NULL,
    /* version                */    XtVersion,
    /* callback_private       */    NULL,
    /* tm_table               */    defaultTranslations,
    /* query_geometry         */    QueryGeometry,
    /* display_accelerator    */    XtInheritDisplayAccelerator,
    /* extension        */    NULL
  },
  { /* composite fields */
    /* geometry_manager       */    Geometry_manager,
    /* change_managed         */    XtInheritChangeManaged,
    /* insert_child           */    XtInheritInsertChild,
    /* delete_child           */    XtInheritDeleteChild,
    /* extension        */    NULL
  },
  { /* canvas fields */
    /* empty                  */    0
  }
};

WidgetClass canvasWidgetClass = (WidgetClass)&canvasClassRec;

/*
 * Initialize a widget instance by allocating graphics contexts.
 */
static void
Initialize(request, new)
Widget request, new;
{
      Display *d;
      XGCValues gcv;
      CanvasWidget w = (CanvasWidget) new;

      gcv.function = GXcopy;
      gcv.plane_mask = AllPlanes;
      /* the drawGC has function GXcopy as function set, that clears all
         the previous contents of the drawable used with it. */
      w->canvas.copyGC = XtGetGC((Widget) w, GCFunction | GCPlaneMask, &gcv);

      /* gcv.font = w->canvas.font->fid; */
      gcv.function = GXcopy;
      gcv.plane_mask = AllPlanes;
      w->canvas.drawGC = XtGetGC((Widget) w, GCFunction | GCPlaneMask, &gcv);

      /* finally, the clearGC simply allows to clear the drawable by
         using XFillRectangle. foreground is set equal to background */
      gcv.foreground = w->core.background_pixel;
      w->canvas.clearGC = XtGetGC((Widget) w, GCForeground, &gcv);

      /* create pixmap, that is copied to the window on exposes
         or on request by CanvasUpdateArea */
      d = XtDisplay(w);
      w->canvas.pxmw = w->core.width;
      w->canvas.pxmh = w->core.height;
      w->canvas.picture = XCreatePixmap(d, DefaultRootWindow(d),
                              w->core.width, w->core.height,
                              DefaultDepth(d, DefaultScreen(d)));

}

/*
 * Realize a widget instance.  Allocate pixmaps, create the window, etc.
 */
static void
Realize(gw, valueMask, attr)
XSetWindowAttributes *attr;
XtValueMask *valueMask;
Widget gw;
{
      CanvasWidget w = (CanvasWidget) gw;

      /* look if we have an idle-cursor set in the resources,
         and if so, tell the window we create about it. */
      if ((attr->cursor = w->canvas.idle_cursor) != None)
            *valueMask |= CWCursor;

      /* create our window */
      XtCreateWindow(gw, InputOutput, (Visual *) CopyFromParent,
                   *valueMask, attr);

      /* clear the cpixmap */
      canvasClearPicture(w);
}

/*
 * Destroy a widget instance.
 */
static void
Destroy(gw)
Widget gw;
{
      CanvasWidget w = (CanvasWidget) gw;

      /* release the allocated space for all the GCs... */
      XtReleaseGC((Widget) w, w->canvas.drawGC);
      XtReleaseGC((Widget) w, w->canvas.copyGC);
      XtReleaseGC((Widget) w, w->canvas.clearGC);

      /* ...and for the pixmaps */
      XFreePixmap(XtDisplay(w), w->canvas.picture);
}

/*
 * Widget was resized
 */
static void
Resize(w)
Widget w;
{
  CanvasWidget cw = (CanvasWidget) w;

  fprintf(stderr, "Canvas: Resize called ! wid=%u, height=%u\n",
      (unsigned)cw->core.width, (unsigned)cw->core.height);
}

/*
 * Geometry is queried by parent
 */
static XtGeometryResult
QueryGeometry(w, intended, preferred)
Widget w;
XtWidgetGeometry *intended, *preferred;
{
  CanvasWidget cw = (CanvasWidget) w;

  preferred->request_mode = CWWidth | CWHeight;
  preferred->width = cw->canvas.pxmw;
  preferred->height = cw->canvas.pxmh;
  if (preferred->width == w->core.width &&
      preferred->height == w->core.height)
    return XtGeometryNo;
  if (((intended->request_mode & (CWWidth|CWHeight)) == (CWWidth|CWHeight)) &&
      intended->width == preferred->width &&
      intended->height == preferred->height)
    return XtGeometryYes;
  return XtGeometryAlmost;
}

/*
 * Redisplay a widget after an expose event by copying data from the pixmaps.
 */
static void
Redisplay(gw, event, region)
Region region;
XEvent *event;
Widget gw;
{
      CanvasWidget w = (CanvasWidget) gw;
      XExposeEvent *e = (XExposeEvent *) event;
      
      canvasBusy(w);

      /* copy the bounding box of the exposed area from the pixmaps
         into the window to redraw the destroyed contents. */

      /* underlay the picture at first.... */
      XCopyArea(XtDisplay(gw), w->canvas.picture, XtWindow(gw),
              w->canvas.copyGC, e->x, e->y,
              (Dimension) e->width, (Dimension) e->height,
              e->x, e->y);
  
      canvasIdle(w);
}

static void
Notify(w,event,params,num_params)
Widget w;
XEvent *event;
String *params;         /* unused */
Cardinal *num_params;   /* unused */
{
    static XPoint xp;
    CanvasWidget cw = (CanvasWidget)w;

    switch (event->type) {
      case ButtonPress:
          xp.x = event->xbutton.x;
          xp.y = event->xbutton.y;
          XtCallCallbackList(w, cw->canvas.callbacks, (XtPointer) &xp);
          break;
      default:
          XtCallCallbackList(w, cw->canvas.callbacks, (XtPointer) NULL);
          break;
    }
}

static Boolean
SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args)
{
  CanvasWidget curcw = (CanvasWidget) current;
  CanvasWidget reqcw = (CanvasWidget) request;
  CanvasWidget newcw = (CanvasWidget) new;
  Pixmap pxm;
  Display *d;
  Dimension oldw, oldh, neww, newh;

  fprintf(stderr, "Canvas: SetValues called\n");
  /* if the geometry is changed, we have to create a new pixmap. */
  oldw = curcw->canvas.pxmw;
  oldh = curcw->canvas.pxmh;
  neww = reqcw->core.width;
  newh = reqcw->core.height;
  if ((oldw != neww) || (oldh != newh)) {
    d = XtDisplay(current);
    pxm = XCreatePixmap(d, DefaultRootWindow(d),
                  neww, newh,
                  DefaultDepth(d, DefaultScreen(d)));
    /* we don't need this here because the main-program must redraw
       the screen anyway if geometry has changed. */
    /* XCopyArea(d, curcw->canvas.picture, pxm, curcw->canvas.copyGC,
            0, 0, min(neww, oldw), min(newh, oldh), 0, 0); */
    /* now free the old pixmap */
    XFreePixmap(d, curcw->canvas.picture);
    /* and set the changed values. */
    newcw->canvas.picture = pxm;
    newcw->canvas.pxmw = neww;
    newcw->canvas.pxmh = newh;
  }
  /* Redisplay needed ? I think not... */
  return False;
}

static XtGeometryResult
Geometry_manager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *new)
{
/*  use the following to allow geometry-changes by the child - ACZ
    if (request->request_mode & CWX)
      w->core.x = request->x;
    if (request->request_mode & CWY)
      w->core.y = request->y;
    if (request->request_mode & CWWidth)
      w->core.width = request->width;
    if (request->request_mode & CWHeight)
      w->core.height = request->height;
    if (request->request_mode & CWBorderWidth)
      w->core.border_width = request->border_width;
    return XtGeometryNo;
*/
    fprintf(stderr, "geometry manager called !\n");
    return XtGeometryYes;
}

/*
 * Draw line segments on the "picture" pixmap of the widget.
 */
void
canvasDrawSegmentsPicture(w, segments, nsegments)
XSegment *segments;
CanvasWidget w;
int nsegments;
{
      XDrawSegments(XtDisplay(w), w->canvas.picture, w->canvas.drawGC,
                  segments, nsegments);
}

/*
 * Draw a line on the "picture" pixmap of the widget.
 */
void
canvasDrawLinePicture(w, x1, y1, x2, y2)
int x1, y1, x2, y2;
CanvasWidget w;
{
      XDrawLine(XtDisplay(w), w->canvas.picture, w->canvas.drawGC,
              x1, y1, x2, y2);
}

/*
 * Draw text on the "picture" pixmap of the widget.
 */
void
canvasDrawTextPicture(w, x, y, str)
CanvasWidget w;
char *str;
int x, y;
{
      XDrawString(XtDisplay(w), w->canvas.picture, w->canvas.drawGC,
                x, y, str, strlen(str));
}

/*
 * Clear the "picture" pixmap of the widget.
 */
void
canvasClearPicture(w)
CanvasWidget w;
{
      XFillRectangle(XtDisplay(w), w->canvas.picture, w->canvas.clearGC,
                   0, 0, w->core.width, w->core.height);
}

/*
 * Update the window of the widget with the "picture" and "scratch" pixmaps.
 */
void
canvasUpdateArea(w, x, y, width, height)
CanvasWidget w;
unsigned x, y, width, height;
{
      unsigned cw, ch;

      cw = w->core.width;
      ch = w->core.height;
      if (x >= cw) x = cw-1;
      if (y >= ch) y = ch-1;
      if (x + width > cw) width = cw - x;
      if (y + height > ch) height = ch - y;
      /* copy the picture-pixmap onto the window */
      XCopyArea(XtDisplay(w), w->canvas.picture, XtWindow(w),
              w->canvas.copyGC, x, y, width, height,
              x, y);
}

/*
 * Get one of the GCs of the Widget
 */
GC
canvasGetGC(w, type)
CanvasWidget w;
unsigned type;
{
    switch(type) {
      case CanvasDrawGC:  return (w->canvas.drawGC);
      case CanvasCopyGC:  return (w->canvas.copyGC);
      case CanvasClearGC: return (w->canvas.clearGC);
      default: return (GC)NULL;
    }
}

/*
 * Get one of the Pixmaps of the Widget
 */
Pixmap
canvasGetPixmap(w, type)
CanvasWidget w;
unsigned type;
{
    switch(type) {
      case CanvasPicture:   return (w->canvas.picture);
      default: return (Pixmap)NULL;
    }
}

/*
 * Set the cursor to the busy cursor.
 */
void
canvasBusy(w)
CanvasWidget w;
{
      XSetWindowAttributes attr;

      if ((attr.cursor = w->canvas.busy_cursor) != None) {
            XChangeWindowAttributes(XtDisplay(w), XtWindow(w),
                              CWCursor, &attr);
            XFlush(XtDisplay(w));
      }
}

/*
 * Set the cursor to the idle cursor.
 */
void
canvasIdle(w)
CanvasWidget w;
{
      XSetWindowAttributes attr;

      if ((attr.cursor = w->canvas.idle_cursor) != None) {
            XChangeWindowAttributes(XtDisplay(w), XtWindow(w),
                              CWCursor, &attr);
            XFlush(XtDisplay(w));
      }
}

Generated by  Doxygen 1.6.0   Back to index