This is a demonstration Motif drawing program that I wrote in 1998, when I was still programming in C and using the Motif tool kit. I mention it here only as a curiousity, a relic of the past.
/*
* Sierpinski.c
* 04-Dec-1998
*
* Conrad Halling
* conrad.halling@sphaerula.com
*
* Based in part by drawing.c, which was...
*
* "Written by Dan Heller and Paula Ferguson.
* Copyright 1994, O'Reilly & Associates, Inc.
*
* The X Consortium, and any party obtaining a copy of these files from
* the X Consortium, directly or indirectly, is granted, free of charge, a
* full and unrestricted irrevocable, world-wide, paid up, royalty-free,
* nonexclusive right and license to deal in this software and
* documentation files (the "Software"), including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons who receive
* copies from any such party to do so. This license includes without
* limitation a license to do the foregoing actions under any patents of
* the party supplying this software to the X Consortium."
*/
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <Xm/DrawingA.h>
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Xm/Separator.h>
struct Coords
{
int x; /* X coordinate in the drawing plane */
int y; /* Y coordinate in the drawing plane */
int distance; /* distance from one point to the next, in pixels */
char orientation; /* current orientation (left, up, right, down) */
Display *display; /* X11 display */
Drawable drawable; /* X11 drawable */
GC gc; /* X11 graphics context */
};
/*
* Function prototypes.
*/
static void Advance(
struct Coords *pCoords );
static void DrawCallback(
Widget widget,
XtPointer client_data,
XtPointer call_data );
static void QuitCallback(
Widget widget,
XtPointer pClientData,
XtPointer pCallData );
static void TurnLeft(
struct Coords *pCoords );
static void TurnRight(
struct Coords *pCoords );
static void Zag(
int interval,
struct Coords *pCoords );
static void Zig(
int interval,
struct Coords *pCoords );
int main(
int argc,
char *argv[] )
{
XtAppContext app;
struct Coords coords;
Widget drawButton;
Widget drawingArea;
Widget form;
GC gc;
XGCValues gcv;
Widget quitButton;
Widget separator;
Widget toplevel;
String fallbacks[] =
{
"*fontList: -adobe-helvetica-bold-r-normal-*-*-120-75-75-*-*-iso8859-1",
"*background: gray70",
"*foregound: black",
NULL
};
XtSetLanguageProc( NULL, NULL, NULL );
toplevel = XtVaAppInitialize(
&app, "Demos", NULL, 0,
&argc, argv, fallbacks,
NULL );
/*
* Create a form in which to place the other widgets.
*/
form = XtVaCreateWidget(
"Form", xmFormWidgetClass, toplevel,
NULL );
/*
* Add a pushbutton the user can use to Quit the program.
*/
quitButton = XtVaCreateManagedWidget(
"Quit", xmPushButtonWidgetClass, form,
XmNrightAttachment, XmATTACH_FORM,
XmNrightOffset, 10,
XmNbottomAttachment, XmATTACH_FORM,
XmNbottomOffset, 10,
NULL );
/*
* Add a pushbutton the user can use to clear the canvas.
*/
drawButton = XtVaCreateManagedWidget(
"Draw", xmPushButtonWidgetClass, form,
XmNrightAttachment, XmATTACH_WIDGET,
XmNrightWidget, quitButton,
XmNrightOffset, 10,
XmNbottomAttachment, XmATTACH_FORM,
XmNbottomOffset, 10,
NULL );
/*
* Place a separator above the buttons.
*/
separator = XtVaCreateManagedWidget(
"Separator", xmSeparatorWidgetClass, form,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 0,
XmNrightAttachment, XmATTACH_FORM,
XmNrightOffset, 0,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, quitButton,
XmNbottomOffset, 10,
NULL );
/*
* Create a DrawingArea widget above the separator.
*/
drawingArea = XtVaCreateManagedWidget(
"DrawingArea", xmDrawingAreaWidgetClass, form,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 1,
XmNtopAttachment, XmATTACH_FORM,
XmNtopOffset, 1,
XmNrightAttachment, XmATTACH_FORM,
XmNrightOffset, 1,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, separator,
XmNbottomOffset, 1,
XmNwidth, 400,
XmNheight, 300,
XtVaTypedArg, XmNbackground, XmRString, "gray90", 7,
NULL );
/*
* Since we're going to be drawing, we will be using Xlib routines
* and therefore need a graphics context. Create a GC and attach
* to the DrawingArea's XmNuserData to avoid having to make global
* variable.
*/
gcv.foreground = BlackPixelOfScreen( XtScreen( drawingArea ) );
gc = XCreateGC(
XtDisplay( drawingArea ),
RootWindowOfScreen( XtScreen( drawingArea ) ),
GCForeground,
&gcv );
XtVaSetValues(
drawingArea,
XmNuserData, gc,
NULL );
/*
* Add callbacks for the Draw and Quit buttons.
*/
XtAddCallback( drawButton, XmNactivateCallback, DrawCallback, &coords );
XtAddCallback( quitButton, XmNactivateCallback, QuitCallback, NULL );
/*
* Display the window.
*/
XtManageChild( form );
XtRealizeWidget( toplevel );
/*
* Initialize some of the fields in coords. The rest are initialized
* in DrawCallback(). Calling XtWindow() does not work until we have
* called XtRealizeWidget(); otherwise, a window does not yet exist.
*/
coords.display = XtDisplay( drawingArea );
coords.drawable = XtWindow( drawingArea );
coords.gc = gc;
/*
* Handle events.
*/
XtAppMainLoop( app );
/*
* Not reached. The program exits from QuitCallback().
*/
return ( EXIT_SUCCESS );
}
void DrawCallback(
Widget widget,
XtPointer client_data,
XtPointer call_data )
{
XmDrawingAreaCallbackStruct *cbs;
struct Coords *pCoords;
cbs = ( XmDrawingAreaCallbackStruct * ) call_data;
pCoords = ( struct Coords * ) client_data;
if ( cbs->reason == XmCR_ACTIVATE )
{
/*
* Activated by pushbutton -- clear parent's window.
*/
XClearWindow( pCoords->display, pCoords->drawable );
/*
* Draw into the window.
*/
pCoords->x = 300;
pCoords->y = 230;
pCoords->distance = 5;
pCoords->orientation = 'R';
Zig( 16, pCoords );
}
}
void QuitCallback(
Widget widget,
XtPointer pClientData,
XtPointer pCallData )
{
exit( EXIT_SUCCESS );
}
void Zig(
int interval,
struct Coords *pCoords )
{
assert( 0 != interval );
assert( NULL != pCoords );
if ( 1 == interval )
{
TurnLeft( pCoords );
Advance( pCoords );
TurnLeft( pCoords );
Advance( pCoords );
}
else
{
Zig( interval / 2, pCoords );
Zag( interval / 2, pCoords );
Zig( interval / 2, pCoords );
Zag( interval / 2, pCoords );
}
}
void Zag(
int interval,
struct Coords *pCoords )
{
assert( 0 != interval );
assert( NULL != pCoords );
if ( 1 == interval )
{
TurnRight( pCoords );
Advance( pCoords );
TurnRight( pCoords );
Advance( pCoords );
TurnLeft( pCoords );
Advance( pCoords );
}
else
{
Zag( interval / 2, pCoords );
Zag( interval / 2, pCoords );
Zig( interval / 2, pCoords );
Zag( interval / 2, pCoords );
}
}
void Advance(
struct Coords *pCoords )
{
/*
* Draw a line of distance units.
*/
int newX;
int newY;
switch ( pCoords->orientation )
{
case 'L':
newX = pCoords->x - pCoords->distance;
XDrawLine(
pCoords->display,
pCoords->drawable,
pCoords->gc,
pCoords->x,
pCoords->y,
newX,
pCoords->y );
pCoords->x = newX;
break;
case 'U':
newY = pCoords->y - pCoords->distance;
XDrawLine(
pCoords->display,
pCoords->drawable,
pCoords->gc,
pCoords->x,
pCoords->y,
pCoords->x,
newY );
pCoords->y = newY;
break;
case 'R':
newX = pCoords->x + pCoords->distance;
XDrawLine(
pCoords->display,
pCoords->drawable,
pCoords->gc,
pCoords->x,
pCoords->y,
newX,
pCoords->y );
pCoords->x = newX;
break;
case 'D':
newY = pCoords->y + pCoords->distance;
XDrawLine(
pCoords->display,
pCoords->drawable,
pCoords->gc,
pCoords->x,
pCoords->y,
pCoords->x,
newY );
pCoords->y = newY;
break;
default:
assert( 0 );
break;
}
XFlush( pCoords->display );
usleep( 10 );
}
void TurnLeft(
struct Coords *pCoords )
{
/*
* Change orientation.
*/
switch ( pCoords->orientation )
{
case 'L':
pCoords->orientation = 'D';
break;
case 'U':
pCoords->orientation = 'L';
break;
case 'R':
pCoords->orientation = 'U';
break;
case 'D':
pCoords->orientation = 'R';
break;
default:
assert( 0 );
break;
}
}
void TurnRight(
struct Coords *pCoords )
{
/*
* Change orientation.
*/
switch ( pCoords->orientation )
{
case 'L':
pCoords->orientation = 'U';
break;
case 'U':
pCoords->orientation = 'R';
break;
case 'R':
pCoords->orientation = 'D';
break;
case 'D':
pCoords->orientation = 'L';
break;
default:
assert( 0 );
break;
}
}
To compile this program, you need OpenMotif or Lesstif installed on your system. I provide separate notes for installing OpenMotif 2.2.3 for Mac OS X.
I compiled this program on my Mac OS X laptop using GCC 4.0.1 with the following command:
gcc \ -Wall \ -I/Applications/Darwin/openmotif-2.2.3/include \ -L/usr/X11R6/lib \ -L/Applications/Darwin/openmotif-2.2.3/lib \ Sierpinski.c -lXm -lXt -lSM -lICE -lX11 -o Sierpinski
The program runs correctly, and its output is this:
A Sierpinski fractal