/* This program opens a window and draws the Mandelbrot fractal. The user can click and drag to zoom. Requires Unix/X11. Compile with: cc -o mandelbrot mandelbrot.c -lX11 -lgen on Irix (lgen is for libgen.h) If you have a linux box, try gcc -o mandelbrot mandelbrot.c -lX11 -L/usr/X11R6/lib/ */ #include #include /* malloc(), free() */ #include /* exit() */ #include /* basename() */ #include /* needed for va_start(), va_arg(), va_end() */ #include #include /* #include */ /* #include */ #include /* #define TOGGLEABLE_WINDOW_DECORATIONS */ /* requires Motif header files */ #ifdef TOGGLEABLE_WINDOW_DECORATIONS #include #include #endif /* typedef enum { False = 0, True = 1 } Boolean; */ #ifndef TOGGLEABLE_WINDOW_DECORATIONS typedef unsigned char Boolean; #endif typedef unsigned long Pixel; #define ASSERT(condition) if (!(condition)) { \ printf("Assertion failure, (%s), at line %d in file %s\n", \ #condition, __LINE__, __FILE__ \ ); \ exit(1); \ } struct { char * commandLineName; /* Recall that in X terminology, one *display* can consist of many *screens*. */ Display *display; int screen_num; Screen *screen_ptr; int screenWidth, screenHeight; /* dimensions in pixels */ int screenWidthMM, screenHeightMM; /* dimensions in millimeters */ unsigned int screenDepth; Window rootWindow; Window window; unsigned int windowWidth, windowHeight; /* dimensions in pixels */ Cursor cursor; Pixel blackPixel, whitePixel; GC gc; /* Graphics context. */ } XStuff; struct { short **image; int imageWidth, imageHeight; int currentX, currentY; double minRe, minIm, maxRe, maxIm; int maxIterations; Boolean isImageComplete; Boolean isDragging; int dragX1, dragY1, dragX2, dragY2; Boolean isColorsAllocated; Pixel *colorArray; int numColors; } fractal = { NULL, 0, 0, 0, 0, -2.25, -1.575, 1.95, 1.575, 64, False, False, 0, 0, 0, 0, False, NULL, 0 }; void MakeWindow( char * windowTitle, char * iconTitle, Pixmap iconPixmap, /* Pass (None) for none. */ int minWidth, int minHeight, Boolean isFullScreenAndBorderless, /* Doesn't work too well */ Pixel backgroundPixel, int argc, char *argv[] /* Command line arguments. */ ) { XWMHints *wm_hints; /* Window manager hints. */ XClassHint *class_hints; /* Application class hints. */ XSizeHints *size_hints; /* Preferred window geometry. */ XTextProperty windowName,iconName; /* Special X "strings" */ int windowX, windowY; /* Upper left corner of window. */ unsigned int windowBorderWidth; /* Allocate hint structures. */ if (NULL == (wm_hints = XAllocWMHints()) || NULL == (class_hints = XAllocClassHint()) || NULL == (size_hints = XAllocSizeHints()) ) { fprintf(stderr,"%s: failure allocating memory.\n", XStuff.commandLineName); exit(1); } /* Create text properties. */ if (0 == XStringListToTextProperty(&windowTitle, 1, &windowName) || 0 == XStringListToTextProperty(&iconTitle, 1, &iconName) ) { fprintf(stderr,"%s: structure allocation for text property failed.\n", XStuff.commandLineName); exit(1); } /* Create the main window. */ if (isFullScreenAndBorderless) { windowX = 0; windowY = 0; XStuff.windowWidth = XStuff.screenWidth; XStuff.windowHeight = XStuff.screenHeight; windowBorderWidth = 0; } else { windowX = XStuff.screenWidth/3; windowY = XStuff.screenHeight/3; XStuff.windowWidth = XStuff.screenWidth/3; XStuff.windowHeight = XStuff.screenHeight/3; windowBorderWidth = 0; } XStuff.window = XCreateSimpleWindow(XStuff.display, XStuff.rootWindow, windowX, windowY, XStuff.windowWidth, XStuff.windowHeight, windowBorderWidth, XStuff.blackPixel, XStuff.whitePixel); /* Set window properties. */ wm_hints->flags = StateHint | InputHint; wm_hints->initial_state = NormalState; /* Should window be normal or iconified when first mapped ? */ wm_hints->input = True; /* Does application need keyboard input? */ if (None != iconPixmap) { wm_hints->flags |= IconPixmapHint; wm_hints->icon_pixmap = iconPixmap; } /* These are used by the window manager to get information */ /* about this application from the resource database. */ /* For example, with 4Dwm, you could add lines like these to your ~/.Xdefaults file : 4Dwm*foo.clientDecoration: none 4Dwm*goo.clientDecoration: border resizeh If foo is the name or class of an app's window, then that window will have no window decorations. Similarly, in the case of goo, the window will only have a resizable border. (The clientDecoration resource works the same way with Mwm.) */ class_hints->res_name = XStuff.commandLineName; class_hints->res_class = "MyClassOfApplications"; /* Use USPosition | USSize instead of PPosition | PSize to force hints. */ /* size_hints->flags = PPosition | PSize | PMinSize; */ size_hints->flags = PMinSize; /* In R4 and later, the x, y, width, and height members of XSizeHints should not be set. */ size_hints->min_width = minWidth; size_hints->min_height = minHeight; if (isFullScreenAndBorderless) size_hints->flags |= (USPosition | USSize); XSetWMProperties(XStuff.display, XStuff.window, &windowName, &iconName, argv, argc, size_hints, wm_hints,class_hints); /* Select event types wanted. ConfigureNotify events inform the app that the window has been resized. Processing ConfigureNotify events is more efficient than having to call XGetGeometry() (which requires a reply from the server) on every Expose event. */ XSelectInput(XStuff.display, XStuff.window, ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | /* PointerMotionHintMask | */ /* we don't process mouse motion events */ StructureNotifyMask /* selects CirculateNotify, ConfigureNotify, DestroyNotify, GravityNotify, MapNotify, ReparentNotify, and UnmapNotify */ ); /* Display the window. */ XMapWindow(XStuff.display, XStuff.window); /* Set the background color. */ XSetWindowBackground(XStuff.display, XStuff.window, backgroundPixel); /* Get a graphics context. */ XStuff.gc = XCreateGC(XStuff.display, XStuff.window, 0, NULL); /* Specify black foreground since default window background */ /* is white and default foreground is undefined. */ XSetForeground(XStuff.display, XStuff.gc, XStuff.blackPixel); /* Get geometry information about window */ if (False == XGetGeometry(XStuff.display, XStuff.window, &XStuff.rootWindow, &windowX, &windowY, &XStuff.windowWidth, &XStuff.windowHeight, &windowBorderWidth, &XStuff.screenDepth) ) { fprintf(stderr,"%s: can't get window geometry.\n", XStuff.commandLineName); exit(1); } } /* ================================================================= */ /* The below bitmaps were created with the command "bitmap [filename]". */ #define cursor_width 25 #define cursor_height 25 #define cursor_x_hot 12 #define cursor_y_hot 12 static char cursor_bits[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x55, 0x55, 0x55, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00}; #define mask_width 25 #define mask_height 25 #define mask_x_hot 12 #define mask_y_hot 12 static char mask_bits[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, 0x00, 0x38, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00}; void CreateCursorForWindow() { Pixmap source, mask; XColor foreground, background; foreground.pixel = 0; foreground.red = 65535; foreground.green = 65535; foreground.blue = 65535; foreground.flags = DoRed | DoGreen | DoBlue; foreground.pad = 0; background.pixel = 0; background.red = 0; background.green = 0; background.blue = 0; background.flags = DoRed | DoGreen | DoBlue; background.pad = 0; source = XCreateBitmapFromData(XStuff.display, XStuff.window, cursor_bits, cursor_width, cursor_height); mask = XCreateBitmapFromData(XStuff.display, XStuff.window, mask_bits, mask_width, mask_height); XStuff.cursor = XCreatePixmapCursor(XStuff.display, source, mask, &foreground, &background, cursor_x_hot, cursor_y_hot); XDefineCursor(XStuff.display, XStuff.window, XStuff.cursor); XFreePixmap(XStuff.display, source); XFreePixmap(XStuff.display, mask); } #define MAX_INTERPOLATION_POINTS 20 Pixel *AllocReadOnlySpectrum( int *size_return, int numColorsBetweenPoints, Boolean isWrapAround, ... ) { va_list argPtr; int intArg, red [MAX_INTERPOLATION_POINTS], green [MAX_INTERPOLATION_POINTS], blue [MAX_INTERPOLATION_POINTS]; int numPoints, numColors, delta = 1 + numColorsBetweenPoints, startPoint, endPoint, interpolationCounter, colorIndex, j; float weight; XColor xcolor; Pixel *colorArray; /* BEGIN: gather up paramters. */ va_start(argPtr,isWrapAround); for (j = 0; j < MAX_INTERPOLATION_POINTS; j++) { intArg = va_arg(argPtr, int); if (intArg < 0) break; red [j] = intArg; green[j] = va_arg(argPtr, int); blue [j] = va_arg(argPtr, int); } numPoints = j; va_end(argPtr); /* END: gather up parameters. */ if (isWrapAround) numColors = numPoints * delta; else numColors = numPoints * delta - numColorsBetweenPoints; colorArray = (Pixel*)malloc(numColors * sizeof(Pixel)); colorIndex = 0; startPoint = 0; endPoint = 1; while (endPoint < numPoints) { for (interpolationCounter = 0; interpolationCounter <= numColorsBetweenPoints; interpolationCounter++) { weight = interpolationCounter/(float)delta; xcolor.pixel = 0; xcolor.red = red [startPoint] + weight * (red [endPoint] - red [startPoint]); xcolor.green = green[startPoint] + weight * (green[endPoint] - green[startPoint]); xcolor.blue = blue [startPoint] + weight * (blue [endPoint] - blue [startPoint]); xcolor.flags = DoRed | DoGreen | DoBlue; XAllocColor(XStuff.display, DefaultColormapOfScreen(XStuff.screen_ptr), &xcolor); colorArray[colorIndex] = xcolor.pixel; /* printf("[%d](%d,%d,%d)\n", colorIndex, xcolor.red, xcolor.green, xcolor.blue ); */ colorIndex++; } if (endPoint < startPoint) /* We just finished the last wrap-around loop. */ break; startPoint = endPoint; endPoint++; if (endPoint == numPoints && isWrapAround) /* We now do the last loop necessary to complete wrap-around. */ endPoint = 0; } if (!isWrapAround) { /* Fill in the last color. */ ASSERT(startPoint == numPoints - 1); xcolor.pixel = 0; xcolor.red = red [startPoint]; xcolor.green = green[startPoint]; xcolor.blue = blue [startPoint]; xcolor.flags = DoRed | DoGreen | DoBlue; XAllocColor(XStuff.display, DefaultColormapOfScreen(XStuff.screen_ptr), &xcolor); colorArray[colorIndex] = xcolor.pixel; /* printf("[%d](%d,%d,%d)\n", colorIndex, xcolor.red, xcolor.green, xcolor.blue ); */ colorIndex++; } ASSERT(colorIndex == numColors); *size_return = numColors; return colorArray; } void FreePixelColors() { int j; for (j = 0; j < fractal.numColors; ++j) XFreeColors( XStuff.display, DefaultColormapOfScreen(XStuff.screen_ptr), & fractal.colorArray[j], 1, 0 ); } void AllocateImage(int w,int h) { int j,k; fractal.imageWidth = w; fractal.imageHeight = h; ASSERT(NULL == fractal.image); fractal.image = (short**)malloc((size_t)fractal.imageWidth * sizeof(short*)); ASSERT(NULL != fractal.image); for (j = 0; j < fractal.imageWidth; j++) { fractal.image[j] = (short*)malloc((size_t)fractal.imageHeight * sizeof(short)); ASSERT(NULL != fractal.image[j]); for (k = 0; k < fractal.imageHeight; k++) fractal.image[j][k] = fractal.maxIterations; } fractal.currentX = fractal.currentY = 0; fractal.isImageComplete = False; } void ReleaseImage() { int j; if (fractal.image != NULL) { for (j = 0; j < fractal.imageWidth; j++) free(fractal.image[j]); free(fractal.image); fractal.image = NULL; } fractal.imageWidth = 0; fractal.imageHeight = 0; fractal.isImageComplete = False; } void StartComputations() { double deltaRe, deltaIm; int w,h; deltaRe = fractal.maxRe - fractal.minRe; deltaIm = fractal.maxIm - fractal.minIm; if (deltaRe/deltaIm > (XStuff.windowWidth-1)/(double)(XStuff.windowHeight-1)) { /* The image is too wide to fit in the window. */ w = XStuff.windowWidth; h = deltaIm/deltaRe*(w-1) + 1 + 0.5; /* the 0.5 is to round off */ ASSERT(h <= XStuff.windowHeight); } else { /* The image is too tall, or perhaps it's just right ! */ h = XStuff.windowHeight; w = deltaRe/deltaIm*(h-1) + 1 + 0.5; /* the 0.5 is to round off */ ASSERT(w <= XStuff.windowWidth); } AllocateImage(w,h); fractal.currentX = fractal.currentY = 0; fractal.isImageComplete = False; } void RestartComputations() { ReleaseImage(); StartComputations(); } void PlotAt(int x,int y) { int deltaX, deltaY; int iterations; deltaX = (XStuff.windowWidth - fractal.imageWidth) / 2; deltaY = (XStuff.windowHeight - fractal.imageHeight) / 2; iterations = fractal.image[x][y]; if (iterations >= fractal.maxIterations) XSetForeground(XStuff.display, XStuff.gc, XStuff.blackPixel); else XSetForeground(XStuff.display, XStuff.gc, fractal.colorArray[iterations % fractal.numColors]); XDrawPoint(XStuff.display, XStuff.window, XStuff.gc, deltaX + x, deltaY + y); } void DrawRect(int x1, int y1, int x2, int y2) { int x, y; int deltaX, deltaY; Pixel color, newColor; int iterations; deltaX = (XStuff.windowWidth - fractal.imageWidth) / 2; deltaY = (XStuff.windowHeight - fractal.imageHeight) / 2; /* clip the boundries of the rectangle */ if (x1 < deltaX) x1 = deltaX; if (y1 < deltaY) y1 = deltaY; if (x2 > deltaX + fractal.imageWidth - 1) x2 = deltaX + fractal.imageWidth - 1; if (y2 > deltaY + fractal.imageHeight - 1) y2 = deltaY + fractal.imageHeight - 1; if (!fractal.isImageComplete && y2 > deltaY + fractal.currentY) y2 = deltaY + fractal.currentY; color = XStuff.blackPixel; XSetForeground(XStuff.display, XStuff.gc, color); for (y = y1; y <= y2; y++) for (x = x1; x <= x2; x++) { iterations = fractal.image[x - deltaX][y - deltaY]; if (iterations >= fractal.maxIterations) newColor = XStuff.blackPixel; else newColor = fractal.colorArray[iterations % fractal.numColors]; if (newColor != color) XSetForeground(XStuff.display, XStuff.gc, color = newColor); XDrawPoint(XStuff.display, XStuff.window, XStuff.gc, x, y); } } void Zoom() { double re1,im1,re2,im2,tmp; int deltaX, deltaY, itmp; itmp = fractal.dragX2 - fractal.dragX1; if (itmp < 5 && itmp > -5) return; itmp = fractal.dragY2 - fractal.dragY1; if (itmp < 5 && itmp > -5) return; deltaX = (XStuff.windowWidth - fractal.imageWidth) / 2; deltaY = (XStuff.windowHeight - fractal.imageHeight) / 2; fractal.dragX1 -= deltaX; fractal.dragY1 -= deltaY; fractal.dragX2 -= deltaX; fractal.dragY2 -= deltaY; re1 = fractal.dragX1/(double)(fractal.imageWidth-1) * (fractal.maxRe - fractal.minRe) + fractal.minRe; re2 = fractal.dragX2/(double)(fractal.imageWidth-1) * (fractal.maxRe - fractal.minRe) + fractal.minRe; im1 = fractal.maxIm - fractal.dragY1/(double)(fractal.imageHeight-1) * (fractal.maxIm - fractal.minIm); im2 = fractal.maxIm - fractal.dragY2/(double)(fractal.imageHeight-1) * (fractal.maxIm - fractal.minIm); if (re2 < re1) { tmp = re1; re1 = re2; re2 = tmp; } if (im2 < im1) { tmp = im1; im1 = im2; im2 = tmp; } if (re2 - re1 == 0 || im2 - im1 == 0) return; fractal.minRe = re1; fractal.minIm = im1; fractal.maxRe = re2; fractal.maxIm = im2; RestartComputations(); } void ResizeImageToFillWindow() { double re_center, im_center, width, height; re_center = ( fractal.minRe + fractal.maxRe ) * 0.5; im_center = ( fractal.minIm + fractal.maxIm ) * 0.5; width = fractal.maxRe - fractal.minRe; height = fractal.maxIm - fractal.minIm; /* Here's the resize. */ if (width/height > (XStuff.windowWidth-1)/(double)(XStuff.windowHeight-1)) { /* The image is too wide to fit in the window. */ height = width * (XStuff.windowHeight-1)/(double)(XStuff.windowWidth-1); } else { /* The image is too tall, or perhaps it's just right ! */ width = height * (XStuff.windowWidth-1)/(double)(XStuff.windowHeight-1); } /* Slam the results back in. */ fractal.minRe = re_center - width * 0.5; fractal.maxRe = re_center + width * 0.5; fractal.minIm = im_center - height * 0.5; fractal.maxIm = im_center + height * 0.5; RestartComputations(); } void ZoomInOnCenter( double magnificationFactor ) { double re_center, im_center, width, height; re_center = ( fractal.minRe + fractal.maxRe ) * 0.5; im_center = ( fractal.minIm + fractal.maxIm ) * 0.5; width = fractal.maxRe - fractal.minRe; height = fractal.maxIm - fractal.minIm; /* Here's the zoom-in. */ width /= magnificationFactor; height /= magnificationFactor; /* Slam the results back in. */ fractal.minRe = re_center - width * 0.5; fractal.maxRe = re_center + width * 0.5; fractal.minIm = im_center - height * 0.5; fractal.maxIm = im_center + height * 0.5; RestartComputations(); } void ContinueComputations() { double px, py, zx, zy, zx_new, zy_new; int j; if (NULL == fractal.image || fractal.isImageComplete) return; px = fractal.currentX/(double)(fractal.imageWidth-1) * (fractal.maxRe - fractal.minRe) + fractal.minRe; py = fractal.maxIm - fractal.currentY/(double)(fractal.imageHeight-1) * (fractal.maxIm - fractal.minIm); zx = 0.0; zy = 0.0; for (j = 0; j < fractal.maxIterations; j++) { zx_new = zx*zx - zy*zy + px; zy_new = 2*zx*zy + py; zx = zx_new; zy = zy_new; if (zx*zx + zy*zy >= 4) break; } fractal.image[fractal.currentX][fractal.currentY] = j; PlotAt(fractal.currentX, fractal.currentY); fractal.currentX++; if (fractal.imageWidth == fractal.currentX) { fractal.currentX = 0; fractal.currentY++; if (fractal.imageHeight == fractal.currentY) { fractal.currentY = 0; fractal.isImageComplete = True; } } } main(int argc, char *argv[]) { XEvent event; /* Structure for event information */ int keyCode; int j; /* If display_name is not specified by the user, it should be set to NULL, which causes XOpenDisplay() to connect to the server specified in the UNIX environment DISPLAY variable. setenv DISPLAY host:display.screen (C shell) setenv DISPLAY elvis:0.0 DISPLAY=host:display.screen; export DISPLAY (Bourne shell) */ char *display_name = NULL; /* Server to connect to */ Boolean stillRunning = True; #ifdef TOGGLEABLE_WINDOW_DECORATIONS Boolean hasNoWindowDecorations = False; PropMotifWmHints mwm_hints; Atom mwm_hints_atom; #endif XStuff.commandLineName = basename(argv[0]); /* Connect to the X server. */ if (NULL == (XStuff.display = XOpenDisplay(display_name))) { fprintf(stderr,"%s: cannot connect to X server %s\n", XStuff.commandLineName, XDisplayName(display_name)); exit(1); } XStuff.screen_num = DefaultScreen (XStuff.display); XStuff.screen_ptr = DefaultScreenOfDisplay(XStuff.display); XStuff.screenWidth = DisplayWidth (XStuff.display, XStuff.screen_num); XStuff.screenHeight = DisplayHeight (XStuff.display, XStuff.screen_num); XStuff.screenWidthMM = DisplayWidthMM (XStuff.display, XStuff.screen_num); XStuff.screenHeightMM = DisplayHeightMM (XStuff.display, XStuff.screen_num); XStuff.rootWindow = RootWindow (XStuff.display, XStuff.screen_num); XStuff.blackPixel = BlackPixel (XStuff.display, XStuff.screen_num); XStuff.whitePixel = WhitePixel (XStuff.display, XStuff.screen_num); printf( "This program displays the Mandelbrot fractal.\n" "To zoom in on a region, click and drag with the left mouse button.\n" "Keys:\n" " keypad \"+\"/\"-\" Zoom in/out, centered\n" " \"i\" Modify the number of iterations\n" " space Resize image to fill the window\n" #ifdef TOGGLEABLE_WINDOW_DECORATIONS " F10 Toggle window decorations\n" " (requires Motif-like window manager)\n" #endif " escape Quit\n" "Press Enter to begin ... " ); getchar(); MakeWindow("Mandelbrot Fractal","z -> z^2 + p",None,0,0, False, XStuff.blackPixel,argc,argv ); CreateCursorForWindow(); fractal.colorArray = AllocReadOnlySpectrum( & fractal.numColors, 15, #if 1 /* a rainbow scheme */ True, 65535, 0, 0, 65535, 65535, 0, 0, 65535, 0, 0, 65535, 65535, 0, 0, 65535, 65535, 0, 65535, #else /* icy cold colours */ False, 65535, 0, 65535, 0, 65535, 0, 0, 65535, 65535, 0, 0, 65535, #endif -1 ); fractal.isColorsAllocated = True; StartComputations(); while (stillRunning) { if (!fractal.isImageComplete && NULL != fractal.image) { while (0 == XEventsQueued(XStuff.display, QueuedAfterFlush)) { for (j = 0; j < 100; j++) ContinueComputations(); } } XNextEvent(XStuff.display, &event); switch(event.type) { case Expose: #if 0 /* we draw each exposed region seperately; no skipping */ /* Unless this is the last contiguous expose, don't draw the window. */ if (event.xexpose.count != 0) break; /* Only *contiguous* expose events can be skipped. Searching through the event queue */ /* to find the last expose event would skip over intervening ConfigureNotify events. */ #endif /* The exposed area is given by the x,y,width,height fields in event.xexpose */ ASSERT(fractal.isColorsAllocated && NULL != fractal.colorArray); ASSERT(NULL != fractal.image); DrawRect(event.xexpose.x, event.xexpose.y, event.xexpose.x + event.xexpose.width - 1, event.xexpose.y + event.xexpose.height - 1); break; case ConfigureNotify: if ( XStuff.windowWidth != event.xconfigure.width || XStuff.windowHeight != event.xconfigure.height ) { XStuff.windowWidth = event.xconfigure.width; XStuff.windowHeight = event.xconfigure.height; RestartComputations(); } break; case ButtonPress: /* event.xbutton has members x, y, state, button state == is a combination of Button1Mask | ... | Button5Mask | ControlMask | ShiftMask | LockMask | Mod1Mask | ... | Mod5Mask button == one of Button1, ..., Button5 */ fractal.isDragging = True; fractal.dragX1 = event.xbutton.x; fractal.dragY1 = event.xbutton.y; break; case ButtonRelease: if (fractal.isDragging) { fractal.dragX2 = event.xbutton.x; fractal.dragY2 = event.xbutton.y; fractal.isDragging = False; Zoom(); } break; case KeyPress: switch (keyCode = XLookupKeysym(&event.xkey, 0)) { case XK_space: ResizeImageToFillWindow(); break; case XK_KP_Add: ZoomInOnCenter( 3.0 ); break; case XK_KP_Subtract: ZoomInOnCenter( 1.0 / 3.0 ); break; case XK_Up: ; break; case XK_Down: ; break; case XK_Right: ; break; case XK_Left: ; break; case XK_1: ; break; case XK_i: case XK_I: printf("\nMax number of iterations is currently %d\n",fractal.maxIterations); printf("Enter new max:\n"); scanf("%d",&j); if (j >= 1 && j != fractal.maxIterations) { fractal.maxIterations = j; RestartComputations(); } break; #ifdef TOGGLEABLE_WINDOW_DECORATIONS case XK_F10: hasNoWindowDecorations = ! hasNoWindowDecorations; mwm_hints_atom = XInternAtom ( XStuff.display, _XA_MOTIF_WM_HINTS, False ); mwm_hints.flags = (int) MWM_HINTS_DECORATIONS; mwm_hints.decorations = hasNoWindowDecorations ? 0 : MWM_DECOR_ALL; /* : MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_RESIZEH | MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE | MWM_DECOR_MENU; */ XChangeProperty( XStuff.display, XStuff.window, mwm_hints_atom, mwm_hints_atom, 32, PropModeReplace, (unsigned char *) & mwm_hints, PROP_MWM_HINTS_ELEMENTS ); break; #endif case XK_Escape: stillRunning = False; break; } break; case KeyRelease: ; break; #if 0 case MotionNotify: /* get the latest motion event */ while(XCheckMaskEvent(XStuff.display,PointerMotionMask,&event)) ; /* event.xmotion has members x, y, state, is_hint */ /* ... */ break; #endif default: break; } /* switch */ } /* while */ FreePixelColors(); ReleaseImage(); XFreeGC(XStuff.display, XStuff.gc); XFreeCursor(XStuff.display, XStuff.cursor); XCloseDisplay(XStuff.display); }