2
* $Header: /home/orchestra5/davy/stuff/misc/xsat/RCS/Canvas.c,v 1.1 92/04/10 14:08:02 davy Exp $
4
* Copyright 1992 by David A. Curry
5
* Adapted for use with ACfax by Andreas Czechanowski
7
* Permission to use, copy, modify, distribute, and sell this software and its
8
* documentation for any purpose is hereby granted without fee, provided that
9
* the above copyright notice appear in all copies and that both that copyright
10
* notice and this permission notice appear in supporting documentation. The
11
* author makes no representations about the suitability of this software for
12
* any purpose. It is provided "as is" without express or implied warranty.
14
* Code for the Canvas widget. Based in part on the Template widget from
15
* the X11R5 distribution; I also looked quite a bit at the code from the
16
* "xproof" program to figure out how to set things up.
20
* Engineering Computer Network
21
* 1285 Electrical Engineering Building
22
* West Lafayette, IN 47907
26
* Revision 1.1 92/04/10 14:08:02 davy
30
#include <X11/IntrinsicP.h>
31
#include <X11/StringDefs.h>
32
#include <X11/cursorfont.h>
38
static void Destroy();
39
static void Realize();
40
static void Redisplay();
42
static XtGeometryResult QueryGeometry();
43
static Boolean SetValues();
44
static XtGeometryResult Geometry_manager();
45
static void Initialize();
49
void canvasClearPicture();
50
void canvasUpdateArea();
53
* Canvas widget translations
55
static char defaultTranslations[] =
56
"<Btn1Down>: notify()";
58
* Canvas widget actions
60
static XtActionsRec actionsList[] = {
64
* Canvas widget resources.
66
/* offset to a canvas-element in the widget-structure */
67
#define offset(field) XtOffsetOf(CanvasRec,canvas.field)
68
/* offset to a core-element in the widget-stucture */
69
#define goffset(field) XtOffsetOf(CanvasRec,core.field)
70
static XtResource resources[] = {
71
{ XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
72
goffset(background_pixel), XtRString, "white" },
73
{ XtNidleCursor, XtCCursor, XtRCursor, sizeof(Cursor),
74
offset(idle_cursor), XtRString, "left_ptr" },
75
{ XtNbusyCursor, XtCCursor, XtRCursor, sizeof(Cursor),
76
offset(busy_cursor), XtRString, "watch" },
77
{ XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
78
offset(callbacks), XtRCallback, (XtPointer)NULL},
80
{ XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
81
offset(font), XtRString, XtDefaultFont },
87
CanvasClassRec canvasClassRec = {
89
/* superclass */ (WidgetClass) &compositeClassRec,
90
/* class_name */ "Canvas",
91
/* widget_size */ sizeof(CanvasRec),
92
/* class_initialize */ NULL,
93
/* class_part_initialize */ NULL,
94
/* class_inited */ FALSE,
95
/* initialize */ Initialize,
96
/* initialize_hook */ NULL,
97
/* realize */ Realize,
98
/* actions */ actionsList,
99
/* num_actions */ XtNumber(actionsList),
100
/* resources */ resources,
101
/* num_resources */ XtNumber(resources),
102
/* xrm_class */ NULLQUARK,
103
/* compress_motion */ TRUE,
104
/* compress_exposure */ TRUE,
105
/* compress_enterleave */ TRUE,
106
/* visible_interest */ FALSE,
107
/* destroy */ Destroy,
109
/* expose */ Redisplay,
110
/* set_values */ SetValues,
111
/* set_values_hook */ NULL,
112
/* set_values_almost */ XtInheritSetValuesAlmost,
113
/* get_values_hook */ NULL,
114
/* accept_focus */ NULL,
115
/* version */ XtVersion,
116
/* callback_private */ NULL,
117
/* tm_table */ defaultTranslations,
118
/* query_geometry */ QueryGeometry,
119
/* display_accelerator */ XtInheritDisplayAccelerator,
122
{ /* composite fields */
123
/* geometry_manager */ Geometry_manager,
124
/* change_managed */ XtInheritChangeManaged,
125
/* insert_child */ XtInheritInsertChild,
126
/* delete_child */ XtInheritDeleteChild,
129
{ /* canvas fields */
134
WidgetClass canvasWidgetClass = (WidgetClass)&canvasClassRec;
137
* Initialize a widget instance by allocating graphics contexts.
140
Initialize(request, new)
145
CanvasWidget w = (CanvasWidget) new;
147
gcv.function = GXcopy;
148
gcv.plane_mask = AllPlanes;
149
/* the drawGC has function GXcopy as function set, that clears all
150
the previous contents of the drawable used with it. */
151
w->canvas.copyGC = XtGetGC((Widget) w, GCFunction | GCPlaneMask, &gcv);
153
/* gcv.font = w->canvas.font->fid; */
154
gcv.function = GXcopy;
155
gcv.plane_mask = AllPlanes;
156
w->canvas.drawGC = XtGetGC((Widget) w, GCFunction | GCPlaneMask, &gcv);
158
/* finally, the clearGC simply allows to clear the drawable by
159
using XFillRectangle. foreground is set equal to background */
160
gcv.foreground = w->core.background_pixel;
161
w->canvas.clearGC = XtGetGC((Widget) w, GCForeground, &gcv);
163
/* create pixmap, that is copied to the window on exposes
164
or on request by CanvasUpdateArea */
166
w->canvas.pxmw = w->core.width;
167
w->canvas.pxmh = w->core.height;
168
w->canvas.picture = XCreatePixmap(d, DefaultRootWindow(d),
169
w->core.width, w->core.height,
170
DefaultDepth(d, DefaultScreen(d)));
175
* Realize a widget instance. Allocate pixmaps, create the window, etc.
178
Realize(gw, valueMask, attr)
179
XSetWindowAttributes *attr;
180
XtValueMask *valueMask;
183
CanvasWidget w = (CanvasWidget) gw;
185
/* look if we have an idle-cursor set in the resources,
186
and if so, tell the window we create about it. */
187
if ((attr->cursor = w->canvas.idle_cursor) != None)
188
*valueMask |= CWCursor;
190
/* create our window */
191
XtCreateWindow(gw, InputOutput, (Visual *) CopyFromParent,
194
/* clear the cpixmap */
195
canvasClearPicture(w);
199
* Destroy a widget instance.
205
CanvasWidget w = (CanvasWidget) gw;
207
/* release the allocated space for all the GCs... */
208
XtReleaseGC((Widget) w, w->canvas.drawGC);
209
XtReleaseGC((Widget) w, w->canvas.copyGC);
210
XtReleaseGC((Widget) w, w->canvas.clearGC);
212
/* ...and for the pixmaps */
213
XFreePixmap(XtDisplay(w), w->canvas.picture);
223
CanvasWidget cw = (CanvasWidget) w;
225
fprintf(stderr, "Canvas: Resize called ! wid=%u, height=%u\n",
226
(unsigned)cw->core.width, (unsigned)cw->core.height);
230
* Geometry is queried by parent
232
static XtGeometryResult
233
QueryGeometry(w, intended, preferred)
235
XtWidgetGeometry *intended, *preferred;
237
CanvasWidget cw = (CanvasWidget) w;
239
preferred->request_mode = CWWidth | CWHeight;
240
preferred->width = cw->canvas.pxmw;
241
preferred->height = cw->canvas.pxmh;
242
if (preferred->width == w->core.width &&
243
preferred->height == w->core.height)
245
if (((intended->request_mode & (CWWidth|CWHeight)) == (CWWidth|CWHeight)) &&
246
intended->width == preferred->width &&
247
intended->height == preferred->height)
248
return XtGeometryYes;
249
return XtGeometryAlmost;
253
* Redisplay a widget after an expose event by copying data from the pixmaps.
256
Redisplay(gw, event, region)
261
CanvasWidget w = (CanvasWidget) gw;
262
XExposeEvent *e = (XExposeEvent *) event;
266
/* copy the bounding box of the exposed area from the pixmaps
267
into the window to redraw the destroyed contents. */
269
/* underlay the picture at first.... */
270
XCopyArea(XtDisplay(gw), w->canvas.picture, XtWindow(gw),
271
w->canvas.copyGC, e->x, e->y,
272
(Dimension) e->width, (Dimension) e->height,
279
Notify(w,event,params,num_params)
282
String *params; /* unused */
283
Cardinal *num_params; /* unused */
286
CanvasWidget cw = (CanvasWidget)w;
288
switch (event->type) {
290
xp.x = event->xbutton.x;
291
xp.y = event->xbutton.y;
292
XtCallCallbackList(w, cw->canvas.callbacks, (XtPointer) &xp);
295
XtCallCallbackList(w, cw->canvas.callbacks, (XtPointer) NULL);
301
SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args)
303
CanvasWidget curcw = (CanvasWidget) current;
304
CanvasWidget reqcw = (CanvasWidget) request;
305
CanvasWidget newcw = (CanvasWidget) new;
308
Dimension oldw, oldh, neww, newh;
310
fprintf(stderr, "Canvas: SetValues called\n");
311
/* if the geometry is changed, we have to create a new pixmap. */
312
oldw = curcw->canvas.pxmw;
313
oldh = curcw->canvas.pxmh;
314
neww = reqcw->core.width;
315
newh = reqcw->core.height;
316
if ((oldw != neww) || (oldh != newh)) {
317
d = XtDisplay(current);
318
pxm = XCreatePixmap(d, DefaultRootWindow(d),
320
DefaultDepth(d, DefaultScreen(d)));
321
/* we don't need this here because the main-program must redraw
322
the screen anyway if geometry has changed. */
323
/* XCopyArea(d, curcw->canvas.picture, pxm, curcw->canvas.copyGC,
324
0, 0, min(neww, oldw), min(newh, oldh), 0, 0); */
325
/* now free the old pixmap */
326
XFreePixmap(d, curcw->canvas.picture);
327
/* and set the changed values. */
328
newcw->canvas.picture = pxm;
329
newcw->canvas.pxmw = neww;
330
newcw->canvas.pxmh = newh;
332
/* Redisplay needed ? I think not... */
336
static XtGeometryResult
337
Geometry_manager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *new)
339
/* use the following to allow geometry-changes by the child - ACZ
340
if (request->request_mode & CWX)
341
w->core.x = request->x;
342
if (request->request_mode & CWY)
343
w->core.y = request->y;
344
if (request->request_mode & CWWidth)
345
w->core.width = request->width;
346
if (request->request_mode & CWHeight)
347
w->core.height = request->height;
348
if (request->request_mode & CWBorderWidth)
349
w->core.border_width = request->border_width;
352
fprintf(stderr, "geometry manager called !\n");
353
return XtGeometryYes;
357
* Draw line segments on the "picture" pixmap of the widget.
360
canvasDrawSegmentsPicture(w, segments, nsegments)
365
XDrawSegments(XtDisplay(w), w->canvas.picture, w->canvas.drawGC,
366
segments, nsegments);
370
* Draw a line on the "picture" pixmap of the widget.
373
canvasDrawLinePicture(w, x1, y1, x2, y2)
377
XDrawLine(XtDisplay(w), w->canvas.picture, w->canvas.drawGC,
382
* Draw text on the "picture" pixmap of the widget.
385
canvasDrawTextPicture(w, x, y, str)
390
XDrawString(XtDisplay(w), w->canvas.picture, w->canvas.drawGC,
391
x, y, str, strlen(str));
395
* Clear the "picture" pixmap of the widget.
398
canvasClearPicture(w)
401
XFillRectangle(XtDisplay(w), w->canvas.picture, w->canvas.clearGC,
402
0, 0, w->core.width, w->core.height);
406
* Update the window of the widget with the "picture" and "scratch" pixmaps.
409
canvasUpdateArea(w, x, y, width, height)
411
unsigned x, y, width, height;
417
if (x >= cw) x = cw-1;
418
if (y >= ch) y = ch-1;
419
if (x + width > cw) width = cw - x;
420
if (y + height > ch) height = ch - y;
421
/* copy the picture-pixmap onto the window */
422
XCopyArea(XtDisplay(w), w->canvas.picture, XtWindow(w),
423
w->canvas.copyGC, x, y, width, height,
428
* Get one of the GCs of the Widget
436
case CanvasDrawGC: return (w->canvas.drawGC);
437
case CanvasCopyGC: return (w->canvas.copyGC);
438
case CanvasClearGC: return (w->canvas.clearGC);
439
default: return (GC)NULL;
444
* Get one of the Pixmaps of the Widget
447
canvasGetPixmap(w, type)
452
case CanvasPicture: return (w->canvas.picture);
453
default: return (Pixmap)NULL;
458
* Set the cursor to the busy cursor.
464
XSetWindowAttributes attr;
466
if ((attr.cursor = w->canvas.busy_cursor) != None) {
467
XChangeWindowAttributes(XtDisplay(w), XtWindow(w),
469
XFlush(XtDisplay(w));
474
* Set the cursor to the idle cursor.
480
XSetWindowAttributes attr;
482
if ((attr.cursor = w->canvas.idle_cursor) != None) {
483
XChangeWindowAttributes(XtDisplay(w), XtWindow(w),
485
XFlush(XtDisplay(w));