dheller@cory.Berkeley.EDU (Dan Heller) (06/01/88)
I have gone over the paint program distributed with the X11R2 code
enough to make it work as it was probably intended by the original
author (except that I added rubberbanding). The changes included
here are intended to patch only -- no additional features are added
and serious attempts at buidling a draw program should not be based
on this model. See the modified README after applying these patches.
--------------------------------------------------------------------
*** paint.orig/README Thu Feb 25 23:01:33 1988
--- README Tue May 31 15:29:00 1988
***************
*** 1,12 ****
Read carefully; this is the only documentation there is!
The paint program takes no paramaters. It makes a connection to
! $DISPLAY, and opens a window near the upper-left corner of the screen.
Paint is very modal. There are keyboard commands to change the modes.
Type the commands at the window on the X11 display. The current mode
! is displayed on stdout. (I would like to display the current mode on
! the X11 window, but I couldn't get fonts to work.)
Some of the keyboard commands take an integer argument. To specify an
argument, type a number (with an optional minus sign) before the key
--- 1,22 ----
+ This program has been updated by Dan Heller <island!argv@sun.com>
+ to make it work with X11R2 and in the manner probably desired by
+ the original author. Reader's note: "paint" is a misnomer because
+ this package maintains a display list of objects. Paint packages
+ are not object based, but pixel based. This is really a simplified
+ draw package intended to show examples of how some of the graphics
+ rendering machanisms work. What follows is the original README file
+ modified to reflect my changes.
+ --Dan Heller 5/31/88 <island!argv@sun.com>
+ --------
+
Read carefully; this is the only documentation there is!
The paint program takes no paramaters. It makes a connection to
! $DISPLAY.
Paint is very modal. There are keyboard commands to change the modes.
Type the commands at the window on the X11 display. The current mode
! is displayed on the top of the window.
Some of the keyboard commands take an integer argument. To specify an
argument, type a number (with an optional minus sign) before the key
***************
*** 14,23 ****
a Draw an arc. When the user drags through a rectangle with the
mouse, an arc will be inscribed in that rectangle (from angle1 to angle2).
A Draw a filled arc. Same as above, but arc will be filled.
! C Clear the window.
f Change the alu function. This takes an argument from 0 to 15.
--- 24,34 ----
a Draw an arc. When the user drags through a rectangle with the
mouse, an arc will be inscribed in that rectangle (from angle1 to angle2).
+ Default set to 360 degrees and 0 degrees (a complete ellipse).
A Draw a filled arc. Same as above, but arc will be filled.
! C Clear the window (also clears display list).
f Change the alu function. This takes an argument from 0 to 15.
***************
*** 24,34 ****
l Draw lines. When the user drags through the window, a line
will be drawn from where he presses the button to where he releases it.
! p Draw polygons. Specify several points on the screen by
! clicking with the left button. Specify the last point with the right
! button. A polygon will be drawn connecting the points in order. (This
! isn't a real polygon; it won't automatically connect the first and last
! points for you. This is just a test for XLines().)
P Draw filled polygons. Same as above, but the polygon will be
filled. (The first and last points are connected by the server.)
--- 35,41 ----
l Draw lines. When the user drags through the window, a line
will be drawn from where he presses the button to where he releases it.
! p Draw open polygon (freehand draw). Release button to complete polygon.
P Draw filled polygons. Same as above, but the polygon will be
filled. (The first and last points are connected by the server.)
***************
*** 41,52 ****
t Change the thickness (a.k.a. "line width"). The line width is
set to the argument.
! , Set the value of angle1 to the argument. The units are
! degrees. (This was supposed to be a '<', but because I have to work to
! detect shifted characters, ',' was easier.)
! . Set the value of angle2 to the argument. (As above, this was
! supposed to be a '>'.)
! Paint will also refresh itself on expose windows. The code to do this
! correctly with clipping rectangles is currently commented out.
--- 48,61 ----
t Change the thickness (a.k.a. "line width"). The line width is
set to the argument.
! < or , Set the value of angle1 to the argument. The units are in degrees.
! > or . Set the value of angle2 to the argument. The units are in degrees.
! q quit program.
!
! Paint will also refresh itself on expose windows. This action redraws each
! object in the display list -- so it is very slow (esp on a sun).
!
! The Polygon routines leave screen dust (stray pixels) because of Xor-ing.
! This is due to the method used to "rubberband" freehand curves.
*** paint.orig/main.c Thu Feb 25 23:01:20 1988
--- main.c Tue May 31 16:32:26 1988
***************
*** 36,42 ****
Display *dpy;
! int shiftbit = FALSE;
HandleKey(event)
XEvent *event;
--- 36,42 ----
Display *dpy;
! int save_func, save_width;
HandleKey(event)
XEvent *event;
***************
*** 47,60 ****
static int arg = 0;
static int argval = 1;
static int sgn = 0;
! code = event->xkey.keycode;
! if (code == 174) {
! shiftbit = TRUE;
return;
! }
! c = GetCharFromCode(code);
! if (c >= 'a' && c <= 'z' && shiftbit)
! c += 'A' - 'a';
switch (c) {
case 'C':
XClearWindow(dpy, window);
--- 47,60 ----
static int arg = 0;
static int argval = 1;
static int sgn = 0;
! KeySym k;
! char b[2];
!
! (void) XLookupString(event, b, 2, &k, NULL);
! c = b[0];
! if (IsModifierKey(k))
return;
!
switch (c) {
case 'C':
XClearWindow(dpy, window);
***************
*** 75,85 ****
break;
case 'p':
stat.mode = polygon;
- npoints = 0;
break;
case 'P':
stat.mode = filledpolygon;
- npoints = 0;
break;
case 'a':
stat.mode = arc;
--- 75,83 ----
***************
*** 88,102 ****
stat.mode = filledarc;
break;
case 'f':
! stat.func = arg;
! if (arg != argval)
stat.func = GXinvert;
- gcvalues.function = stat.func;
- XChangeGC(dpy, gc, GCFunction, &gcvalues);
break;
case ',':
stat.angle1 = arg * 64;
break;
case '.':
stat.angle2 = arg * 64;
break;
--- 86,99 ----
stat.mode = filledarc;
break;
case 'f':
! if ((stat.func = arg) < GXclear || arg > GXset)
stat.func = GXinvert;
break;
+ case '<':
case ',':
stat.angle1 = arg * 64;
break;
+ case '>':
case '.':
stat.angle2 = arg * 64;
break;
***************
*** 120,129 ****
return;
case 't':
stat.thickness = argval;
- gcvalues.line_width = stat.thickness;
- XChangeGC(dpy, gc, GCLineWidth, &gcvalues);
break;
default:
printf("Unknown code %d (%c)\n", event->xkey.keycode, c);
return;
}
--- 117,127 ----
return;
case 't':
stat.thickness = argval;
break;
+ case 'q':
+ exit(0);
default:
+ XBell(dpy, 50);
printf("Unknown code %d (%c)\n", event->xkey.keycode, c);
return;
}
***************
*** 133,175 ****
sgn = 1;
}
- HandleKeyUp(event)
- XEvent *event;
- {
- if (event->xkey.keycode == 174)
- shiftbit = FALSE;
- }
-
DisplayMode()
{
! char str[500];
! sprintf(str,
! "Mode %s; Thickness %d; Function %s; angle1 %.2f; angle2 %.2f",
! StringForMode(stat.mode), stat.thickness, StringForFunction(stat.func),
! stat.angle1 / 64.0, stat.angle2/64.0);
! XDrawImageString(dpy, window, gc, 0, 0, str, strlen(str));
! printf("%s\n", str);
}
- HandleButtonDown(event)
- XEvent *event;
- {
- switch (stat.mode) {
- case line:
- case rect:
- case filledrect:
- case arc:
- case filledarc:
- curx = event->xbutton.x;
- cury = event->xbutton.y;
- break;
- }
- }
-
ImagePtr NewImage()
{
ImagePtr image;
! image = (ImagePtr) malloc(sizeof(ImageRec));
image->stat = stat;
image->npoints = 0;
image->points = (XPoint *) malloc(1);
--- 131,154 ----
sgn = 1;
}
DisplayMode()
{
! char str[500], *p;
! sprintf(str, "Mode %s, Thickness %d, Function %s",
! StringForMode(stat.mode), stat.thickness, StringForFunction(stat.func));
! if (stat.mode == arc || stat.mode == filledarc) {
! p = str + strlen(str);
! sprintf(p, ", angle1 %g, angle2 %g",
! stat.angle1 / 64.0, stat.angle2 / 64.0);
! } else
! strcat(str, " "); /* to erase angles string */
! XDrawImageString(dpy, window, gc, 5, 10, str, strlen(str));
}
ImagePtr NewImage()
{
ImagePtr image;
! image = (ImagePtr) calloc((unsigned)1, sizeof(ImageRec));
image->stat = stat;
image->npoints = 0;
image->points = (XPoint *) malloc(1);
***************
*** 180,209 ****
ImagePtr image;
int x, y;
{
! npoints = image->npoints++;
image->points = (XPoint *)
realloc(image->points, sizeof(XPoint) * image->npoints);
! image->points[npoints].x = x;
! image->points[npoints].y = y;
! image->next = NULL;
! image->drawn = FALSE;
}
! DrawImage(image)
ImagePtr image;
{
XGCValues gcvalues;
int x1, x2, y1, y2, x, y, width, height;
gcvalues.function = image->stat.func;
gcvalues.line_width = image->stat.thickness;
XChangeGC(dpy, gc, GCFunction | GCLineWidth, &gcvalues);
! if (!image->drawn) {
if (lastimage)
lastimage->next = image;
else
firstimage = image;
lastimage = image;
- image->drawn = TRUE;
}
if (image->npoints == 2) {
x1 = image->points[0].x;
--- 159,186 ----
ImagePtr image;
int x, y;
{
! image->npoints++;
image->points = (XPoint *)
realloc(image->points, sizeof(XPoint) * image->npoints);
! image->points[image->npoints - 1].x = x;
! image->points[image->npoints - 1].y = y;
}
! DrawImage(image, append)
ImagePtr image;
{
XGCValues gcvalues;
int x1, x2, y1, y2, x, y, width, height;
+
gcvalues.function = image->stat.func;
gcvalues.line_width = image->stat.thickness;
XChangeGC(dpy, gc, GCFunction | GCLineWidth, &gcvalues);
! if (append) {
if (lastimage)
lastimage->next = image;
else
firstimage = image;
lastimage = image;
}
if (image->npoints == 2) {
x1 = image->points[0].x;
***************
*** 244,253 ****
}
}
!
! HandleButtonUp(event)
XEvent *event;
{
int newx, newy;
newx = event->xbutton.x;
newy = event->xbutton.y;
--- 221,243 ----
}
}
! HandleButtonDown(event)
XEvent *event;
{
+ XGCValues gcvalues;
+
+ curx = event->xbutton.x;
+ cury = event->xbutton.y;
+ save_func = stat.func;
+ save_width = stat.thickness;
+ gcvalues.function = stat.func = GXxor;
+ gcvalues.line_width = stat.thickness = 1;
+ XChangeGC(dpy, gc, GCFunction | GCLineWidth, &gcvalues);
+ }
+
+ ButtonMove(event)
+ XEvent *event;
+ {
int newx, newy;
newx = event->xbutton.x;
newy = event->xbutton.y;
***************
*** 257,280 ****
case filledrect:
case arc:
case filledarc:
! image = NewImage();
! StuffPoint(image, curx, cury);
! StuffPoint(image, newx, newy);
! DrawImage(image);
break;
case polygon:
case filledpolygon:
! if (image == NULL || image->stat.mode != stat.mode)
image = NewImage();
StuffPoint(image, newx, newy);
! if (event->xbutton.button == Button3) {
! DrawImage(image);
}
}
curx = newx;
cury = newy;
- printf("*");
- fflush(stdout);
}
XRectangle rects[500];
--- 247,321 ----
case filledrect:
case arc:
case filledarc:
! if (!image) {
! image = NewImage();
! StuffPoint(image, curx, cury);
! StuffPoint(image, newx, newy);
! } else {
! DrawImage(image, FALSE); /* erase old image */
! image->points[1].x = newx;
! image->points[1].y = newy;
! }
! DrawImage(image, FALSE);
break;
case polygon:
case filledpolygon:
! if (image == NULL) {
image = NewImage();
+ StuffPoint(image, curx, cury);
+ }
StuffPoint(image, newx, newy);
! /* build line piece by piece, don't rerender the whole polyline */
! XDrawLine(dpy, window, gc, curx, cury, newx, newy);
! curx = newx;
! cury = newy;
! }
! }
!
! HandleButtonUp(event)
! XEvent *event;
! {
! int newx, newy;
! newx = event->xbutton.x;
! newy = event->xbutton.y;
! if (image) {
! if (stat.mode == filledpolygon)
! image->stat.mode = polygon;
! DrawImage(image, FALSE);
! if (stat.mode == filledpolygon)
! image->stat.mode = filledpolygon;
! image->stat.func = save_func;
! image->stat.thickness = save_width;
! }
! /* change from xor/single linewidth mode to real render mode */
! stat.func = save_func;
! stat.thickness = save_width;
! if (!image) /* a single click without movement won't create an object */
! return;
! switch (stat.mode) {
! case line:
! case rect:
! case filledrect:
! case arc:
! case filledarc:
! if (image->npoints > 1) {
! image->points[1].x = newx;
! image->points[1].y = newy;
! break;
}
+ case polygon:
+ case filledpolygon:
+ StuffPoint(image, newx, newy);
+ /*
+ puts("polygon points:");
+ for (newx = 0; newx < image->npoints; newx++)
+ printf("%d, %d\n", image->points[newx].x, image->points[newx].y);
+ */
}
+ DrawImage(image, TRUE);
+ image = NULL; /* reinitialize */
curx = newx;
cury = newy;
}
XRectangle rects[500];
***************
*** 295,301 ****
XSetClipRectangles(dpy, gc, 0, 0, rects, numrects, Unsorted);
numrects = 0;
for (image = firstimage; image; image = image->next)
! DrawImage(image);
rects[0].x = 0;
rects[0].y = 0;
rects[0].width = 9999;
--- 336,342 ----
XSetClipRectangles(dpy, gc, 0, 0, rects, numrects, Unsorted);
numrects = 0;
for (image = firstimage; image; image = image->next)
! DrawImage(image, FALSE);
rects[0].x = 0;
rects[0].y = 0;
rects[0].width = 9999;
***************
*** 311,327 ****
Visual visual;
XSetWindowAttributes attributes;
XGCValues gcvalues;
! if ((dpy = XOpenDisplay("")) == NULL)
Punt("Couldn't open display!");
- InitUtil();
windowwidth = 400;
windowheight = 400;
stat.thickness = 1;
! stat.func = GXinvert;
stat.angle1 = 0;
stat.angle2 = 360 * 64;
! foreground = WhitePixel(dpy, DefaultScreen(dpy));
! background = BlackPixel(dpy, DefaultScreen(dpy));
font = XLoadFont(dpy, "fixed");
visual.visualid = CopyFromParent;
attributes.background_pixel = background;
--- 352,367 ----
Visual visual;
XSetWindowAttributes attributes;
XGCValues gcvalues;
! if ((dpy = XOpenDisplay(NULL)) == NULL)
Punt("Couldn't open display!");
windowwidth = 400;
windowheight = 400;
stat.thickness = 1;
! save_func = stat.func = GXinvert;
stat.angle1 = 0;
stat.angle2 = 360 * 64;
! background = WhitePixel(dpy, DefaultScreen(dpy));
! foreground = BlackPixel(dpy, DefaultScreen(dpy));
font = XLoadFont(dpy, "fixed");
visual.visualid = CopyFromParent;
attributes.background_pixel = background;
***************
*** 328,340 ****
attributes.border_pixel = foreground;
attributes.backing_store = Always;
window = XCreateWindow(dpy, RootWindow(dpy, DefaultScreen(dpy)),
! 20, 20, windowwidth, windowheight, 1,
! DefaultDepth(dpy, DefaultScreen(dpy)), CopyFromParent, &visual,
! CWBackPixel | CWBorderPixel /*| CWBackingStore */,
! &attributes);
XChangeProperty(dpy, window, XA_WM_NAME, XA_STRING, 8,
PropModeReplace, "Paint", 5);
! MyXSelectInput(dpy, window, KeyPressMask | KeyReleaseMask | ButtonPressMask
| ButtonReleaseMask | ButtonMotionMask | ExposureMask);
XMapWindow(dpy, window);
gcvalues.foreground = foreground;
--- 368,379 ----
attributes.border_pixel = foreground;
attributes.backing_store = Always;
window = XCreateWindow(dpy, RootWindow(dpy, DefaultScreen(dpy)),
! 20, 20, windowwidth, windowheight, 1,
! DefaultDepth(dpy, DefaultScreen(dpy)), CopyFromParent, &visual,
! CWBackPixel | CWBorderPixel /*| CWBackingStore */, &attributes);
XChangeProperty(dpy, window, XA_WM_NAME, XA_STRING, 8,
PropModeReplace, "Paint", 5);
! MyXSelectInput(dpy, window, KeyPressMask | ButtonPressMask
| ButtonReleaseMask | ButtonMotionMask | ExposureMask);
XMapWindow(dpy, window);
gcvalues.foreground = foreground;
***************
*** 348,363 ****
&gcvalues);
stat.mode = line;
image = firstimage = lastimage = NULL;
! DisplayMode();
! while (1) {
XNextEvent(dpy, &event);
switch(event.type) {
case KeyPress:
HandleKey(&event);
break;
- case KeyRelease:
- HandleKeyUp(&event);
- break;
case ButtonPress:
HandleButtonDown(&event);
break;
--- 387,398 ----
&gcvalues);
stat.mode = line;
image = firstimage = lastimage = NULL;
! for (;;) {
XNextEvent(dpy, &event);
switch(event.type) {
case KeyPress:
HandleKey(&event);
break;
case ButtonPress:
HandleButtonDown(&event);
break;
***************
*** 365,373 ****
--- 400,410 ----
HandleButtonUp(&event);
break;
case MotionNotify:
+ ButtonMove(&event);
break;
case Expose:
RepaintDisplay(&event);
+ DisplayMode();
break;
}
}
*** paint.orig/paint.h Thu Feb 25 23:01:20 1988
--- paint.h Fri May 27 15:55:41 1988
***************
*** 5,10 ****
--- 5,12 ----
#include <stdio.h>
#include "X11/Xlib.h"
#include "X11/Xatom.h"
+ #include "X11/Xutil.h"
+ #include "X11/keysym.h"
/***********************************************************
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
***************
*** 33,39 ****
#define max(x, y) ((x) > (y) ? (x) : (y))
#define abs(x) ((x) < 0 ? (-(x)) : (x))
! typedef enum {line, rect, filledrect, arc, filledarc, polygon, filledpolygon} ModeType;
typedef struct {
ModeType mode;
--- 35,49 ----
#define max(x, y) ((x) > (y) ? (x) : (y))
#define abs(x) ((x) < 0 ? (-(x)) : (x))
! typedef enum {
! line,
! rect,
! filledrect,
! arc,
! filledarc,
! polygon,
! filledpolygon
! } ModeType;
typedef struct {
ModeType mode;
***************
*** 47,53 ****
int npoints;
XPoint *points;
struct _ImageRec *next;
- int drawn;
} ImageRec, *ImagePtr;
#ifndef TRUE
--- 57,62 ----
***************
*** 68,76 ****
ext Window window;
ext int windowheight, windowwidth;
ext long foreground, background;
-
- ext XPoint points[1000];
- ext int npoints;
extern GC XCreateGC();
extern XFontStruct *XFont();
--- 77,82 ----
*** paint.orig/util.c Thu Feb 25 23:01:21 1988
--- util.c Fri May 27 15:53:07 1988
***************
*** 48,92 ****
}
- InitUtil()
- {
- int i;
- for (i=0 ; i<256 ; i++) ChrToCode[i] = 0;
- ChrToCode['a'] = 194; ChrToCode['b'] = 217; ChrToCode['c'] = 206;
- ChrToCode['d'] = 205; ChrToCode['e'] = 204; ChrToCode['f'] = 210;
- ChrToCode['g'] = 216; ChrToCode['h'] = 221; ChrToCode['i'] = 230;
- ChrToCode['j'] = 226; ChrToCode['k'] = 231; ChrToCode['l'] = 236;
- ChrToCode['m'] = 227; ChrToCode['n'] = 222; ChrToCode['o'] = 235;
- ChrToCode['p'] = 240; ChrToCode['q'] = 193; ChrToCode['r'] = 209;
- ChrToCode['s'] = 199; ChrToCode['t'] = 215; ChrToCode['u'] = 225;
- ChrToCode['v'] = 211; ChrToCode['w'] = 198; ChrToCode['x'] = 200;
- ChrToCode['y'] = 220; ChrToCode['z'] = 195; ChrToCode['0'] = 239;
- ChrToCode['1'] = 192; ChrToCode['2'] = 197; ChrToCode['3'] = 203;
- ChrToCode['4'] = 208; ChrToCode['5'] = 214; ChrToCode['6'] = 219;
- ChrToCode['7'] = 224; ChrToCode['8'] = 229; ChrToCode['9'] = 234;
- ChrToCode['`'] = 191; ChrToCode['~'] = 191; ChrToCode['!'] = 192;
- ChrToCode['#'] = 203; ChrToCode['$'] = 208;
- ChrToCode['%'] = 214; ChrToCode['&'] = 224;
- ChrToCode['*'] = 229; ChrToCode['('] = 234; ChrToCode[')'] = 239;
- ChrToCode['-'] = 249; ChrToCode['='] = 245;
- ChrToCode['+'] = 245; ChrToCode['['] = 250; ChrToCode['{'] = 250;
- ChrToCode[']'] = 246; ChrToCode['}'] = 246; ChrToCode[';'] = 242;
- ChrToCode[':'] = 242; ChrToCode['\''] = 251; ChrToCode['"'] = 251;
- ChrToCode['\\'] = 247; ChrToCode['|'] = 247; ChrToCode[','] = 232;
- ChrToCode['.'] = 237; ChrToCode['/'] = 243; ChrToCode['?'] = 243;
- ChrToCode['<'] = 201; ChrToCode['>'] = 201; ChrToCode['\t'] = 190;
- ChrToCode[' '] = 212;
- for (i=0 ; i<256 ; i++) CodeToChr[ChrToCode[i]] = i;
- }
-
-
- GetCharFromCode(n)
- int n;
- {
- return CodeToChr[n];
- }
-
-
char *StringForMode(mode)
ModeType mode;
{
--- 48,53 ----
Dan Heller <island!argv@sun.com>