home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) Ken W. Marks 1989, 1990.
- */
-
- #include <stdio.h>
- #include <fcntl.h>
- #include <math.h>
- #include <X11/IntrinsicP.h>
- #include <X11/StringDefs.h>
- #include <X11/XWDFile.h>
- #include <Chaos.h>
- #include <LocalDefs.h>
- #include <Ipc.h>
- #include <Menu.h>
- #include <MenuItems.h>
- #include <CanvasP.h>
- #include <Task.h>
- #include <Queue.h>
- #include <Colormap.h>
-
- static Cardinal pad_amount[] = {0, 3, 2, 1};
-
- /* macro for padding a length to an even multiple of 4 (uses pad_amount[]) */
- #define PAD(length) ((length) + pad_amount[(length) & 3])
-
- #define STARTING_RADIUS 2.5
-
- #define IN_BOUNDS_X(w, x) ((int) ((x) < 0 ? 0 : \
- (x) >= (w)->core.width ? \
- (w)->core.width - 1 : (x)))
-
- #define IN_BOUNDS_Y(w, y) ((int) ((y) < 0 ? 0 : \
- (y) >= (w)->core.height ? \
- (w)->core.height - 1 : (y)))
-
- #define MAX_SAVE_IMAGE_SIZE 65536
-
-
- #define offset(field) XtOffset(CanvasWidget,canvas.field)
- #define goffset(field) XtOffset(Widget,core.field)
-
- static XtResource resources[] = {
- {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
- goffset(width), XtRString, "512"},
- {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
- goffset(height), XtRString, "512"},
- };
-
- #undef offset
- #undef goffset
-
- static void CanvasInitialize(), CanvasRealize(), CanvasResize();
- static void CanvasRedisplay();
-
- static void CanvasRegister(), CanvasUnregister(), CanvasMessage();
- static void CanvasBtnDown(), CanvasBtnUp(), CanvasMotion();
- static void CanvasMoveBox();
- static void CanvasQuit();
- static void CanvasReverse();
- static void CanvasStartStop();
- extern void MenuPopup();
-
- static XtActionsRec canvas_actions[] =
- {
- {"unregister", CanvasUnregister},
- {"receive_msg", CanvasMessage},
- {"press", CanvasBtnDown},
- {"release", CanvasBtnUp},
- {"move", CanvasMotion},
- {"popup", MenuPopup},
- {"quit", CanvasQuit},
- {"reverse", CanvasReverse},
- {"start_stop", CanvasStartStop},
- };
-
- static char canvas_translations[] =
- "<Destroy>: unregister()\n\
- <Prop>: receive_msg()\n\
- <Btn1Down>: press()\n\
- <Btn1Up>: release()\n\
- <Btn1Motion>: move()\n\
- <Btn3Down>: popup(menu_popup.menu)\n\
- Ctrl<Key>C: quit()\n\
- <Key>Q: quit()\n\
- <Key>Return: reverse()\n\
- <Key>0x20: start_stop()\n\
- ";
-
- #define superclass (&widgetClassRec)
-
- CanvasClassRec canvasClassRec = {
- {
- /* core fields */
- /* superclass */ (WidgetClass) superclass,
- /* class_name */ "Canvas",
- /* widget_size */ sizeof(CanvasRec),
- /* class_initialize */ NULL,
- /* class_part_initialize */ NULL,
- /* class_inited */ FALSE,
- /* initialize */ CanvasInitialize,
- /* initialize_hook */ NULL,
- /* realize */ CanvasRealize,
- /* actions */ canvas_actions,
- /* num_actions */ XtNumber(canvas_actions),
- /* resources */ resources,
- /* resource_count */ XtNumber(resources),
- /* xrm_class */ NULL,
- /* compress_motion */ TRUE,
- /* compress_exposure */ TRUE,
- /* compress_enterleave */ TRUE,
- /* visible_interest */ FALSE,
- /* destroy */ NULL,
- /* resize */ CanvasResize,
- /* expose */ CanvasRedisplay,
- /* set_values */ NULL,
- /* set_values_hook */ NULL,
- /* set_values_almost */ XtInheritSetValuesAlmost,
- /* get_values_hook */ NULL,
- /* accept_focus */ NULL,
- /* version */ XtVersion,
- /* callback_private */ NULL,
- /* tm_table */ canvas_translations,
- /* query_geometry */ NULL,
- }
- };
-
- WidgetClass canvasWidgetClass = (WidgetClass) & canvasClassRec;
-
-
- /************************************************************/
- /******************** Private Procedures ********************/
- /************************************************************/
-
-
- /*ARGSUSED*/
- static void CanvasInitialize(request, new)
- Widget request; /* unused */
- Widget new;
- {
- CanvasWidget w = (CanvasWidget) new;
- Screen *screen = XtScreen(w);
- extern Boolean retain_aspect_ratio;
- extern int iteration_limit;
- extern int task_width;
- extern int task_height;
-
- w->canvas.p_inc = (double) (2 * STARTING_RADIUS) / (w->core.width - 1);
- w->canvas.q_inc = (double) (2 * STARTING_RADIUS) / (w->core.height - 1);
-
- w->canvas.p_inc = w->canvas.q_inc = MAX(w->canvas.p_inc, w->canvas.q_inc);
-
- w->canvas.p_lo = (double) -(w->core.width * w->canvas.p_inc / 2);
- w->canvas.p_hi = (double) (w->canvas.p_lo + w->canvas.p_inc *
- (w->core.width - 1));
-
- w->canvas.q_lo = (double) -(w->core.height * w->canvas.q_inc / 2);
- w->canvas.q_hi = (double) (w->canvas.q_lo + w->canvas.q_inc *
- (w->core.height - 1));
-
- w->canvas.task_x = 0;
- w->canvas.task_y = 0;
- w->canvas.num_drones = 0;
-
- w->canvas.num_colors = CellsOfScreen(screen);
- w->canvas.pixmap = NULL;
- w->canvas.image = NULL;
-
- w->canvas.serial = 0;
- w->canvas.method = MANDELBROT;
-
- w->canvas.finished = False;
- w->canvas.paused = False;
- w->canvas.needs_saving = True;
-
- /* set up the initial iteration limit */
- w->canvas.curr_limit = iteration_limit;
-
- /* set up the initial aspect ratio retention state */
- w->canvas.retain_aspect_ratio = retain_aspect_ratio;
-
- /* set size to zero to force initial change in CanvasChangeTaskSize() */
- w->canvas.curr_task_width = 0;
- w->canvas.curr_task_height = 0;
-
- CanvasChangeTaskSize(new, (unsigned int) task_width,
- (unsigned int) task_height);
- }
-
-
- static void CanvasRealize(widget, valueMask, attrs)
- Widget widget;
- XtValueMask *valueMask;
- XSetWindowAttributes *attrs;
- {
- CanvasWidget w = (CanvasWidget) widget;
- Display *dpy = XtDisplay(w);
- Screen *screen = XtScreen(w);
- XtGCMask valuemask;
- XGCValues gcv;
- extern Colormap colormap;
- extern Widget top_level;
-
- /* we assign the colormap here since we know that the top level shell has
- * been realized. */
- colormap = CreateColormap(dpy, screen, XtWindow(top_level));
-
- XtCreateWindow(widget, InputOutput, (Visual *) CopyFromParent,
- *valueMask, attrs);
-
- gcv.function = GXinvert;
- gcv.plane_mask = 0xff;
- valuemask = GCFunction | GCPlaneMask;
- w->canvas.xor_gc = XtGetGC((Widget) w, valuemask, &gcv);
-
- gcv.background = w->core.background_pixel;
- gcv.fill_style = FillSolid;
- valuemask = GCBackground | GCFillStyle;
- w->canvas.normal_gc = XtGetGC((Widget) w, valuemask, &gcv);
-
- gcv.foreground = BLACK;
- gcv.background = WHITE;
- gcv.fill_style = FillTiled;
- gcv.tile = XmuCreateStippledPixmap(screen, BlackPixelOfScreen(screen),
- WhitePixelOfScreen(screen), (unsigned) DefaultDepthOfScreen(screen));
-
- valuemask = GCForeground | GCBackground | GCTile | GCFillStyle;
- w->canvas.clear_gc = XtGetGC((Widget) w, valuemask, &gcv);
-
- /* Call CanvasResize() to initialize pixmap at creation time since the
- * CanvasRedisplay() will be called before CanvasResize() would. */
- (*XtClass(widget)->core_class.resize) (widget);
- }
-
-
- static void CanvasResize(widget)
- Widget widget;
- {
- CanvasWidget w = (CanvasWidget) widget;
- Display *dpy = XtDisplay(w);
- Window window = XtWindow(w);
- static unsigned int height = 0, width = 0;
-
- if (XtIsRealized(widget) &&
- (height != w->core.height || width != w->core.width))
- {
- height = w->core.height;
- width = w->core.width;
-
- CanvasChangeSize(widget);
-
- MakeTasksStale();
- WasteTasks();
-
- if (w->canvas.pixmap)
- XFreePixmap(dpy, w->canvas.pixmap);
-
- w->canvas.pixmap = XCreatePixmap(dpy, window, width, height,
- w->core.depth);
- if (!w->canvas.pixmap)
- {
- eprintf("Insufficient space for pixmap");
- abort();
- }
-
- XFillRectangle(dpy, w->canvas.pixmap, w->canvas.clear_gc,
- 0, 0, width, height);
- }
- }
-
-
- /*ARGSUSED*/
- static void CanvasRedisplay(widget, event, region)
- Widget widget;
- XExposeEvent *event;
- Region region; /* unused */
- {
- CanvasWidget w = (CanvasWidget) widget;
- Display *dpy = XtDisplay(w);
- Window window = XtWindow(w);
-
- /* Reset any previously drawn zoom box */
- CanvasMoveBox(w, -1, -1, -1, -1);
-
- if (XtIsRealized(widget) == False)
- return;
-
- if (event == NULL)
- XCopyArea(dpy, w->canvas.pixmap, window, w->canvas.normal_gc,
- 0, 0, w->core.width, w->core.height, 0, 0);
- else
- XCopyArea(dpy, w->canvas.pixmap, window, w->canvas.normal_gc,
- event->x, event->y, (unsigned) event->width,
- (unsigned) event->height, event->x, event->y);
- }
-
-
- static void CanvasRegister(widget, resp, offset)
- Widget widget;
- RegistrationResponse *resp;
- unsigned long *offset;
- {
- CanvasWidget w = (CanvasWidget) widget;
- Display *dpy = XtDisplay(w);
- Task *task;
- extern Widget menu;
- extern void ByteSwapLong();
- extern void DroneRegister();
- char hostname[32];
-
- /* Copy hostname before we get a chance to byteswap */
- strcpy(hostname, resp->hostname);
-
- if (resp->byte_order != 0x11223344)
- ByteSwapLong((char *) resp, sizeof(RegistrationResponse));
-
- DroneRegister(resp->window, hostname);
-
- task = AllocTask();
- task->window = resp->window;
-
- if (w->canvas.finished == True || w->canvas.paused == True)
- {
- /* If the widget is not currently drawing, add the new drone to the
- * wait list. */
- TaskNQ(waitQ, task);
- #ifdef DEBUG
- dprintf("Enqueued new drone (window=0x%x) on wait list\n",
- task->window);
- #endif
- }
- else
- {
- /* If the widget is actively drawing, give the drone a task and send
- * it on its way. */
- CanvasFillTask(widget, task);
- TaskNQ(runQ, task);
- if (SendTask(task) == False)
- eprintf("SendTask() failed\n");
- #ifdef DEBUG
- dprintf("Enqueued new drone (window=0x%x) on run list\n",
- task->window);
- #endif
- }
-
- /* select for DestroyNotify events on the drone's window */
- XSelectInput(dpy, task->window, StructureNotifyMask);
-
- /* unstipple draw & redraw menu items when 1st drone added */
- if (w->canvas.num_drones++ == 0)
- {
- (void) MenuChangeSensitivity(menu, MENU_DRAW_ITEM, True);
- (void) MenuChangeSensitivity(menu, MENU_REDRAW_ITEM, True);
- }
- *offset += PAD(sizeof(RegistrationResponse));
- }
-
-
- #define CHEEZY_OPTIMIZATION
-
- void CanvasImageResponse(widget, resp, offset)
- Widget widget;
- ImageResponse *resp;
- unsigned long *offset;
- {
- CanvasWidget w = (CanvasWidget) widget;
- Display *dpy = XtDisplay(w);
- Window window = XtWindow(w);
- Task *task;
- #ifdef CHEEZY_OPTIMIZATION
- int ii;
- char *ptr;
- #else
- int x, y;
- #endif
- unsigned char *value;
- int num_colors = w->canvas.num_colors;
- long width = resp->width;
- long height = resp->height;
-
- if (resp->byte_order != 0x11223344)
- {
- #ifdef DEBUG
- dprintf("ImageResponse\n");
- dprintf(" byte_order: 0x%x\n", resp->byte_order);
- dprintf(" type: %d\n", resp->type);
- dprintf(" serial: %d\n", resp->serial);
- dprintf(" width: %d\n", resp->width);
- dprintf(" height: %d\n", resp->height);
- dprintf(" max_iter: %d\n", resp->max_iter);
- #endif
- eprintf("Incorrect byte ordering (0x%x)\n", resp->byte_order);
- abort();
- }
- if ((task = TaskDQ(runQ, (Window) NULL, resp->serial)) != NULL)
- {
- #ifdef DEBUG
- dprintf("Task located on the runQ\n");
- #endif
- /* dp points past the ImageResponse header */
- value = (unsigned char *) &resp[1];
-
- #ifdef CHEEZY_OPTIMIZATION
- if (num_colors != 256)
- for (ii = height * width, value += ii; ii >= 0; --ii, --value)
- *value %= num_colors;
-
- if (width == w->canvas.image->width)
- (void) memcpy(w->canvas.image->data, (char *) value,
- (int) (height * width));
- else
- {
- /* narrow ImageResponse - copy line at a time */
- ptr = w->canvas.image->data;
- for (ii = height; ii > 0; --ii, value += width,
- ptr += w->canvas.image->width)
- (void) memcpy(ptr, (char *) value, (int) width);
- }
- #else
- if (num_colors == 256)
- /* No need to perform modulus */
- for (y = 0; y < height; ++y)
- for (x = 0; x < width; ++x)
- XPutPixel(w->canvas.image, x, y, *(value++));
- else
- for (y = 0; y < height; ++y)
- for (x = 0; x < width; ++x)
- XPutPixel(w->canvas.image, x, y, *(value++) %
- num_colors);
- #endif
-
- XPutImage(dpy, w->canvas.pixmap, w->canvas.normal_gc,
- w->canvas.image, 0, 0, task->x, task->y, (unsigned) width,
- (unsigned) height);
-
- XCopyArea(dpy, w->canvas.pixmap, window,
- w->canvas.normal_gc, task->x, task->y, (unsigned) width,
- (unsigned) height, task->x, task->y);
-
- /* We need to save everything on the next zoom */
- w->canvas.needs_saving = True;
- }
- else
- {
- /* Was this a stale response from a drone? */
- if ((task = TaskDQ(staleQ, (Window) NULL, resp->serial)) == NULL)
- {
- eprintf("Received bad ImageResponse\n");
- abort();
- }
- #ifdef DEBUG
- dprintf("Task located on the staleQ\n");
- #endif
- }
-
- if (w->canvas.finished == False && w->canvas.paused == False)
- {
- CanvasFillTask(widget, task);
-
- #ifdef DEBUG
- dprintf("Sending following task to run queue:\n");
- PrintTask(task);
- #endif
-
- TaskNQ(runQ, task);
- if (SendTask(task) == False)
- eprintf("SendTask() failed\n");
- }
- else
- {
-
- #ifdef DEBUG
- dprintf("Sending drone 0x%x to the wait queue:\n", task->window);
- #endif
-
- TaskNQ(waitQ, task);
- }
- *offset += PAD(DATA_SIZE(width, height));
- }
-
-
- /***********************************************************/
- /******************** Action Procedures ********************/
- /***********************************************************/
-
-
- /*ARGSUSED*/
- static void CanvasUnregister(widget, event, params, num_params)
- Widget widget;
- XEvent *event;
- String *params; /* unused */
- Cardinal *num_params; /* unused */
- {
- CanvasWidget w = (CanvasWidget) widget;
- XDestroyWindowEvent *ev = (XDestroyWindowEvent *) event;
- Task *task;
- extern Widget menu;
- extern void DroneUnregister();
-
- #ifdef DEBUG
- dprintf("Drone (window=0x%x) has terminated:\n", ev->window);
- #endif
-
- /* update the drone control dialogbox */
- DroneUnregister(ev->window);
-
- /* remove task for window which was destroyed. */
-
- if ((task = TaskDQ(runQ, ev->window, (long) NULL)) != NULL)
- {
- /* Window's task structure was on the run list. The task is placed on
- * the zombie list here for later re-assigned to a new drone */
-
- #ifdef DEBUG
- dprintf("Task removed from run list\n");
- #endif
-
- TaskNQ(zombieQ, task);
- }
- else if ((task = TaskDQ(waitQ, ev->window, (long) NULL)) != NULL)
- {
- /* Window's task structure was on the wait list. Since it wasn't doing
- * anything (but waiting) when it terminated, we can simply purge it
- * from our lists. */
-
- #ifdef DEBUG
- dprintf("Task removed from wait list\n");
- #endif
-
- FreeTask(task);
- }
- else if ((task = TaskDQ(staleQ, ev->window, (long) NULL)) != NULL)
- {
- /* Window's task structure was on the stale list. Since it was
- * calculating a stale task when it terminated, we can simply purge it
- * from our lists. */
-
- #ifdef DEBUG
- dprintf("Task removed from stale list\n");
- #endif
-
- FreeTask(task);
- }
- else
- {
- eprintf("Task structure for drone (window=0x%x) not found!\n",
- ev->window);
- abort();
- }
-
- /* stipple draw and redraw menu items when last drone removed */
- if (--w->canvas.num_drones == 0)
- {
- (void) MenuChangeSensitivity(menu, MENU_DRAW_ITEM, False);
- (void) MenuChangeSensitivity(menu, MENU_REDRAW_ITEM, False);
- }
- }
-
-
- /*ARGSUSED*/
- static void CanvasMessage(widget, event, params, num_params)
- Widget widget;
- XEvent *event;
- String *params; /* unused */
- Cardinal *num_params; /* unused */
- {
- XPropertyEvent *ev = (XPropertyEvent *) event;
- char *msg;
- unsigned long msg_len;
- unsigned long offset;
- GenericMessage generic;
- static int read_ahead = 0;
-
- if (ev->atom != MAILBOX)
- {
- /* must have been some other property (handle as usual) */
- return;
- }
-
- if (ev->state != PropertyNewValue)
- {
- /* generally, ignore the PropertyDelete events. they are generated by
- * our destructive reads on the property and since we can't stop them
- * we must simply ignore them. */
- return;
- }
-
- /* The counter read_ahead will become greater than zero when multiple
- * messages are read from the property in response to a single
- * PropertyNotify event. By keeping track of how many messages we have
- * "read ahead" of the events, we do not attempt to read from an empty
- * property. */
- if (read_ahead-- > 0)
- return;
-
- if (RecvMsg(&msg, &msg_len) == False)
- {
- eprintf("RecvMsg() failed\n");
- return;
- }
-
- offset = 0;
- do
- {
- (void) memcpy((char *) &generic, &msg[offset], sizeof(GenericMessage));
- if (generic.byte_order != 0x11223344)
- ByteSwapLong((char *) &generic, 2 * sizeof(long));
-
- if (generic.type == REGISTRATION_RESPONSE)
- CanvasRegister(widget, (RegistrationResponse *) & msg[offset],
- &offset);
- else if (generic.type == IMAGE_RESPONSE)
- CanvasImageResponse(widget, (ImageResponse *) & msg[offset],
- &offset);
- else
- {
- eprintf("Unknown message type: %d\n", generic.type);
- abort();
- }
- ++read_ahead;
- } while (offset < msg_len);
- free(msg);
- }
-
-
- static void CanvasMoveBox(w, x1, y1, x2, y2)
- CanvasWidget w;
- int x1, y1;
- int x2, y2;
- {
- Display *dpy = XtDisplay(w);
- Window window = XtWindow(w);
- static int last_x1 = -1, last_y1 = -1;
- static int last_x2 = -1, last_y2 = -1;
- static Boolean prev_box = False;
- int tmp;
-
- if (x1 == last_x1 && y1 == last_y1 && x2 == last_x2 && y2 == last_y2)
- return;
-
- if (prev_box)
- XDrawRectangle(dpy, window, w->canvas.xor_gc, last_x1, last_y1,
- (unsigned) (last_x2 - last_x1), (unsigned) (last_y2 - last_y1));
-
- /* Make sure x1 < x2 */
- if (x1 > x2)
- {
- tmp = x1;
- x1 = x2;
- x2 = tmp;
- }
-
- /* Make sure y1 < y2 */
- if (y1 > y2)
- {
- tmp = y1;
- y1 = y2;
- y2 = tmp;
- }
-
- last_x1 = x1;
- last_y1 = y1;
- last_x2 = x2;
- last_y2 = y2;
-
- if (x1 != x2 && y1 != y2)
- {
- XDrawRectangle(dpy, window, w->canvas.xor_gc, x1, y1,
- (unsigned) (x2 - x1), (unsigned) (y2 - y1));
- prev_box = True;
- }
- else
- {
- prev_box = False;
- }
- }
-
-
- /*ARGSUSED*/
- static void CanvasBtnDown(widget, event, params, num_params)
- Widget widget;
- XEvent *event;
- String *params; /* unused */
- Cardinal *num_params; /* unused */
- {
- CanvasWidget w = (CanvasWidget) widget;
- XButtonEvent *ev = (XButtonEvent *) & event->xbutton;
-
-
- w->canvas.x_from = ev->x;
- w->canvas.y_from = ev->y;
-
- CanvasMoveBox(w, w->canvas.x_from, w->canvas.y_from,
- w->canvas.x_from, w->canvas.y_from);
- }
-
-
- /*ARGSUSED*/
- static void CanvasBtnUp(widget, event, params, num_params)
- Widget widget;
- XEvent *event;
- String *params; /* unused */
- Cardinal *num_params; /* unused */
- {
- CanvasWidget w = (CanvasWidget) widget;
- XButtonEvent *ev = (XButtonEvent *) & event->xbutton;
- int tmp;
- extern Widget menu;
-
- w->canvas.x_to = IN_BOUNDS_X(w, ev->x);
- w->canvas.y_to = IN_BOUNDS_Y(w, ev->y);
- CanvasMoveBox(w, w->canvas.x_from, w->canvas.y_from, w->canvas.x_to,
- w->canvas.y_to);
-
- /* Make sure the final points are in "proper" order */
-
- /* Make sure w->canvas.x_from < w->canvas.x_to */
- if (w->canvas.x_from > w->canvas.x_to)
- {
- tmp = w->canvas.x_from;
- w->canvas.x_from = w->canvas.x_to;
- w->canvas.x_to = tmp;
- }
-
- /* Make sure w->canvas.y_from < w->canvas.y_to */
- if (w->canvas.y_from > w->canvas.y_to)
- {
- tmp = w->canvas.y_from;
- w->canvas.y_from = w->canvas.y_to;
- w->canvas.y_to = tmp;
- }
-
- /* stipple zoom menu item if NULL zoom range */
- if (w->canvas.y_from == w->canvas.y_to
- && w->canvas.x_from == w->canvas.x_to)
- (void) MenuChangeSensitivity(menu, MENU_ZOOM_ITEM, False);
- else
- (void) MenuChangeSensitivity(menu, MENU_ZOOM_ITEM, True);
- }
-
-
- /*ARGSUSED*/
- static void CanvasMotion(widget, event, params, num_params)
- Widget widget;
- XEvent *event;
- String *params; /* unused */
- Cardinal *num_params; /* unused */
- {
- CanvasWidget w = (CanvasWidget) widget;
- XMotionEvent *ev = (XMotionEvent *) & event->xmotion;
-
- CanvasMoveBox(w, w->canvas.x_from, w->canvas.y_from, IN_BOUNDS_X(w, ev->x),
- IN_BOUNDS_Y(w, ev->y));
- }
-
-
- /*ARGSUSED*/
- static void CanvasQuit(widget, event, params, num_params)
- Widget widget; /* unused */
- XEvent *event; /* unused */
- String *params; /* unused */
- Cardinal *num_params; /* unused */
- {
- extern void CleanupAndDie();
-
- CleanupAndDie();
- }
-
-
- /*ARGSUSED*/
- static void CanvasReverse(widget, event, params, num_params)
- Widget widget; /* unused */
- XEvent *event; /* unused */
- String *params; /* unused */
- Cardinal *num_params; /* unused */
- {
- extern Widget colormap_dialogbox;
- extern Rotation rotation_dir;
-
- if (rotation_dir == forward)
- rotation_dir = backward;
- else
- rotation_dir = forward;
- }
-
-
- /*ARGSUSED*/
- static void CanvasStartStop(widget, event, params, num_params)
- Widget widget; /* unused */
- XEvent *event; /* unused */
- String *params; /* unused */
- Cardinal *num_params; /* unused */
- {
- extern Boolean rotating;
-
- rotating = !rotating;
- }
-
-
- /***********************************************************/
- /******************** Public Procedures ********************/
- /***********************************************************/
-
-
- void CanvasClear(widget)
- Widget widget;
- {
- CanvasWidget w = (CanvasWidget) widget;
- Display *dpy = XtDisplay(w);
- Window window = XtWindow(w);
- extern int iteration_limit;
- extern int task_width;
- extern int task_height;
-
- /* Reset any previously drawn zoom box */
- CanvasMoveBox(w, -1, -1, -1, -1);
-
- w->canvas.task_x = 0;
- w->canvas.task_y = 0;
- w->canvas.finished = False;
- w->canvas.paused = False;
-
- /* New iteration limit should now be observed */
- w->canvas.curr_limit = iteration_limit;
-
- /* Check and see if a new task size should now be observed */
- CanvasChangeTaskSize(widget, (unsigned int) task_width,
- (unsigned int) task_height);
-
- XFillRectangle(dpy, w->canvas.pixmap, w->canvas.clear_gc,
- 0, 0, w->core.width, w->core.height);
-
- XCopyArea(dpy, w->canvas.pixmap, window, w->canvas.normal_gc,
- 0, 0, w->core.width, w->core.height, 0, 0);
- }
-
-
- void CanvasZoom(widget)
- Widget widget;
- {
- CanvasWidget w = (CanvasWidget) widget;
- double p_mid, q_mid;
- double x_zoom, y_zoom;
- int x_avg, y_avg;
- int width;
- int height;
-
- #ifdef DEBUG
- dprintf("p_lo=%.10G p_hi=%.10G p_inc=%.10G\n",
- w->canvas.p_lo, w->canvas.p_hi, w->canvas.p_inc);
-
- dprintf("q_lo=%.10G q_hi=%.10G q_inc=%.10G\n",
- w->canvas.q_lo, w->canvas.q_hi, w->canvas.q_inc);
- #endif
-
- x_avg = (w->canvas.x_from + w->canvas.x_to) / 2;
- y_avg = (w->canvas.y_from + w->canvas.y_to) / 2;
-
- p_mid = w->canvas.p_lo + w->canvas.p_inc * x_avg;
- q_mid = w->canvas.q_lo + w->canvas.q_inc * y_avg;
-
- width = w->canvas.x_to - w->canvas.x_from;
- height = w->canvas.y_to - w->canvas.y_from;
-
- x_zoom = (double) w->core.width / width;
- y_zoom = (double) w->core.height / height;
-
- if (w->canvas.retain_aspect_ratio)
- x_zoom = y_zoom = MIN(x_zoom, y_zoom);
-
- w->canvas.p_inc /= x_zoom;
- w->canvas.q_inc /= y_zoom;
-
- w->canvas.p_lo = p_mid - w->canvas.p_inc * w->core.width / 2;
- w->canvas.q_lo = q_mid - w->canvas.q_inc * w->core.height / 2;
-
- w->canvas.p_hi = w->canvas.p_lo + w->canvas.p_inc * (w->core.width - 1);
- w->canvas.q_hi = w->canvas.q_lo + w->canvas.q_inc * (w->core.height - 1);
-
- #ifdef DEBUG
- dprintf("p_lo=%.10G p_hi=%.10G p_inc=%.10G\n",
- w->canvas.p_lo, w->canvas.p_hi, w->canvas.p_inc);
-
- dprintf("q_lo=%.10G q_hi=%.10G q_inc=%.10G\n",
- w->canvas.q_lo, w->canvas.q_hi, w->canvas.q_inc);
- #endif
- }
-
-
- void CanvasChangeSize(widget)
- Widget widget;
- {
- CanvasWidget w = (CanvasWidget) widget;
- double p_mid, q_mid;
-
- #ifdef DEBUG
- dprintf("p_lo=%.10G p_hi=%.10G p_inc=%.10G\n",
- w->canvas.p_lo, w->canvas.p_hi, w->canvas.p_inc);
-
- dprintf("q_lo=%.10G q_hi=%.10G q_inc=%.10G\n",
- w->canvas.q_lo, w->canvas.q_hi, w->canvas.q_inc);
- #endif
-
- p_mid = (w->canvas.p_hi + w->canvas.p_lo) / 2;
- q_mid = (w->canvas.q_hi + w->canvas.q_lo) / 2;
-
- w->canvas.p_inc = (double) (w->canvas.p_hi - w->canvas.p_lo) /
- (w->core.width - 1);
- w->canvas.q_inc = (double) (w->canvas.q_hi - w->canvas.q_lo) /
- (w->core.height - 1);
-
- if (w->canvas.retain_aspect_ratio)
- w->canvas.p_inc = w->canvas.q_inc =
- MAX(w->canvas.p_inc, w->canvas.q_inc);
-
- w->canvas.p_lo = p_mid - w->canvas.p_inc * w->core.width / 2;
- w->canvas.q_lo = q_mid - w->canvas.q_inc * w->core.height / 2;
-
- w->canvas.p_hi = w->canvas.p_lo + w->canvas.p_inc * (w->core.width - 1);
- w->canvas.q_hi = w->canvas.q_lo + w->canvas.q_inc * (w->core.height - 1);
-
- #ifdef DEBUG
- dprintf("p_lo=%.10G p_hi=%.10G p_inc=%.10G\n",
- w->canvas.p_lo, w->canvas.p_hi, w->canvas.p_inc);
-
- dprintf("q_lo=%.10G q_hi=%.10G q_inc=%.10G\n",
- w->canvas.q_lo, w->canvas.q_hi, w->canvas.q_inc);
- #endif
-
- w->canvas.task_x = 0;
- w->canvas.task_y = 0;
- w->canvas.finished = True;
- }
-
-
- void CanvasFillTask(widget, task)
- Widget widget;
- Task *task;
- {
- CanvasWidget w = (CanvasWidget) widget;
- Task *unfinished;
- Task *zombie;
- Window saved_window;
- extern int task_width;
- extern int task_height;
-
- /* We need to save everything on the next zoom */
- w->canvas.needs_saving = True;
-
- /* Check first to see if any unfinished task should be completed */
- if ((unfinished = TaskDQ(unfinishedQ, (Window) NULL, (long) NULL)) != NULL)
- {
- /* save the window from the task structure */
- saved_window = task->window;
-
- /* copy in the info from the unfinished task */
- (void) memcpy((char *) task, (char *) unfinished, sizeof(Task));
-
- /* restore original window to task */
- task->window = saved_window;
-
- /* don't need this task anymore */
- FreeTask(unfinished);
- return;
- }
-
- /* Check next to see if any zombie task should be rejuvinated */
- if ((zombie = TaskDQ(zombieQ, (Window) NULL, (long) NULL)) != NULL)
- {
- /* save the window from the task structure */
- saved_window = task->window;
-
- /* copy in the info from the zombie task */
- (void) memcpy((char *) task, (char *) zombie, sizeof(Task));
-
- /* restore original window to task */
- task->window = saved_window;
-
- /* R.I.P. ex-zombie */
- FreeTask(zombie);
- return;
- }
-
- /* Otherwise, fill in the info for the next task... */
-
- task->serial = ++(w->canvas.serial);
- task->limit = w->canvas.curr_limit;
- task->method = w->canvas.method;
-
- /* If we are at the start of the canvas, check to see if we should update
- * the current task width and height. */
- if (w->canvas.task_x == 0 && w->canvas.task_y == 0)
- CanvasChangeTaskSize(widget, (unsigned int) task_width,
- (unsigned int) task_height);
-
- task->width = MIN(w->canvas.curr_task_width, w->core.width -
- w->canvas.task_x);
- task->height = MIN(w->canvas.curr_task_height, w->core.height -
- w->canvas.task_y);
-
- task->x = w->canvas.task_x;
- task->y = w->canvas.task_y;
- task->p_lo = w->canvas.p_lo + task->x * w->canvas.p_inc;
- task->p_hi = task->p_lo + (task->width - 1) * w->canvas.p_inc;
- task->q_lo = w->canvas.q_lo + task->y * w->canvas.q_inc;
- task->q_hi = task->q_lo + (task->height - 1) * w->canvas.q_inc;
-
- w->canvas.finished = False;
-
- w->canvas.task_x += w->canvas.curr_task_width;
- if (w->canvas.task_x >= w->core.width)
- {
- w->canvas.task_x = 0;
- w->canvas.task_y += w->canvas.curr_task_height;
- if (w->canvas.task_y >= w->core.height)
- {
- /* Reset for next drawing session */
- w->canvas.task_x = 0;
- w->canvas.task_y = 0;
- w->canvas.finished = True;
- }
- }
- }
-
-
- void CanvasChangeTaskSize(widget, width, height)
- Widget widget;
- unsigned int width;
- unsigned int height;
- {
- CanvasWidget w = (CanvasWidget) widget;
- Display *dpy = XtDisplay(w);
- Screen *screen = XtScreen(w);
-
- /* no need to update if nothing changed */
- if (w->canvas.curr_task_width == width &&
- w->canvas.curr_task_height == height)
- return;
-
- if (w->canvas.image)
- XDestroyImage(w->canvas.image);
-
- w->canvas.image = XCreateImage(dpy, DefaultVisualOfScreen(screen),
- DefaultDepthOfScreen(screen), ZPixmap, 0, malloc(width * height),
- width, height, 8, 0);
-
- w->canvas.curr_task_width = width;
- w->canvas.curr_task_height = height;
- }
-
-
- void CanvasChangeRetainAspect(widget)
- Widget widget;
- {
- CanvasWidget w = (CanvasWidget) widget;
-
- w->canvas.retain_aspect_ratio = !w->canvas.retain_aspect_ratio;
- }
-
-
- void CanvasUnpause(widget)
- Widget widget;
- {
- CanvasWidget w = (CanvasWidget) widget;
-
- w->canvas.paused = False;
- }
-
-
- void CanvasTouchCanvas(widget)
- Widget widget;
- {
- CanvasWidget w = (CanvasWidget) widget;
-
- w->canvas.needs_saving = TRUE;
- }
-
-
- Boolean CanvasNeedsSaving(widget)
- Widget widget;
- {
- CanvasWidget w = (CanvasWidget) widget;
-
- return (w->canvas.needs_saving);
- }
-
-
- Boolean CanvasSaveImage(fd, widget)
- int fd;
- Widget widget;
- {
- CanvasWidget w = (CanvasWidget) widget;
- Display *dpy = XtDisplay(w);
- XImage *image;
- int image_height, image_width;
- int curr_y = 0;
- XWindowAttributes win_attrib;
- XWDFileHeader header;
- XColor *colors;
- char *name = "Chaos-Image";
- int name_len = strlen(name) + 1;
- unsigned long swap_test = 1;
- Boolean header_written = False;
- int ii;
- extern void ByteSwapShort();
- extern void ByteSwapLong();
-
- image_width = w->core.width;
- image_height = MAX_SAVE_IMAGE_SIZE / image_width;
- image_height = MIN(image_height, w->core.height);
-
- if (!XGetWindowAttributes(dpy, XtWindow(w), &win_attrib))
- {
- eprintf("CanvasSaveImage: cannot get attributes\n");
- return (False);
- }
-
- while (curr_y < w->core.height)
- {
- image = XGetImage(dpy, w->canvas.pixmap, 0, curr_y, image_width,
- image_height, AllPlanes, ZPixmap);
-
- if (header_written == False)
- {
- header_written = True;
- colors = GetColors(w->canvas.num_colors);
-
- header.header_size = (CARD32) sizeof(header) + name_len;
- header.file_version = (CARD32) XWD_FILE_VERSION;
- header.pixmap_format = (CARD32) ZPixmap;
- header.pixmap_depth = (CARD32) image->depth;
- header.pixmap_width = (CARD32) w->core.width;
- header.pixmap_height = (CARD32) w->core.height;
- header.xoffset = (CARD32) image->xoffset;
- header.byte_order = (CARD32) image->byte_order;
- header.bitmap_unit = (CARD32) image->bitmap_unit;
- header.bitmap_bit_order = (CARD32) image->bitmap_bit_order;
- header.bitmap_pad = (CARD32) image->bitmap_pad;
- header.bits_per_pixel = (CARD32) image->bits_per_pixel;
- header.bytes_per_line = (CARD32) image->bytes_per_line;
- header.visual_class = (CARD32) win_attrib.visual->class;
- header.red_mask = (CARD32) win_attrib.visual->red_mask;
- header.green_mask = (CARD32) win_attrib.visual->green_mask;
- header.blue_mask = (CARD32) win_attrib.visual->blue_mask;
- header.bits_per_rgb = (CARD32) win_attrib.visual->bits_per_rgb;
- header.colormap_entries = (CARD32) win_attrib.visual->map_entries;
- header.ncolors = w->canvas.num_colors;
- header.window_width = (CARD32) win_attrib.width;
- header.window_height = (CARD32) win_attrib.height;
- header.window_x = 0;
- header.window_y = 0;
- header.window_bdrwidth = (CARD32) win_attrib.border_width;
-
- if (*(char *) &swap_test)
- {
- ByteSwapLong((char *) &header, sizeof(XWDFileHeader));
- for (ii = 0; ii < w->canvas.num_colors; ++ii)
- {
- ByteSwapLong((char *) &colors[ii].pixel, sizeof(long));
- ByteSwapShort((char *) &colors[ii].red,
- 3 * sizeof(short));
- }
- }
-
- (void) write(fd, (char *) &header, sizeof(XWDFileHeader));
- (void) write(fd, name, name_len);
- (void) write(fd, (char *) colors, sizeof(XColor) *
- w->canvas.num_colors);
- free((char *) colors);
- }
- (void) write(fd, image->data, image->bytes_per_line * image->height);
- XDestroyImage(image);
- curr_y += image_height;
- if (curr_y + image_height > w->core.height)
- image_height = w->core.height - curr_y;
- }
- return (True);
- }
-
-
- Boolean CanvasLoadImage(fd, widget)
- int fd;
- Widget widget;
- {
- CanvasWidget w = (CanvasWidget) widget;
- Display *dpy = XtDisplay(w);
- Screen *screen = XtScreen(w);
- XImage *image;
- char *image_data;
- XWDFileHeader header;
- XColor *colors;
- XSizeHints hints;
- unsigned int image_height, image_width, image_size;
- int curr_y = 0;
- int ii;
- unsigned long swap_test = 1;
- extern Colormap colormap;
- extern Widget top_level;
- extern void ColormapResetControls();
- Boolean resized = False;
- extern long lseek();
-
- (void) read(fd, (char *) &header, sizeof(XWDFileHeader));
-
- if (*(char *) &swap_test)
- ByteSwapLong((char *) &header, sizeof(XWDFileHeader));
-
- /* skip past name (at end of header) */
- (void) lseek(fd, (long) header.header_size, 0);
-
- colors = (XColor *) malloc((unsigned) (sizeof(XColor) * header.ncolors));
- (void) read(fd, (char *) colors, (int) (sizeof(XColor) * header.ncolors));
-
- if (*(char *) &swap_test)
- for (ii = 0; ii < header.ncolors; ++ii)
- {
- ByteSwapLong((char *) &colors[ii].pixel, sizeof(long));
- ByteSwapShort((char *) &colors[ii].red, 3 * sizeof(short));
- }
-
- PutColors(colors, (int) header.ncolors);
- StoreColormap(dpy, colormap);
- (void) free((char *) colors);
-
- /* since a new colormap has been loaded, remove the text from the colormap
- * dialogbox text input field and reset listbox. */
- ColormapResetControls();
-
- if (header.pixmap_width != w->core.width ||
- header.pixmap_height != w->core.height)
- {
- /* We need to resize the before we can load in the image */
- hints.width = header.pixmap_width;
- hints.height = header.pixmap_height;
- hints.flags = USSize;
-
- XSetNormalHints(dpy, XtWindow(top_level), &hints);
-
- XtConfigureWidget(top_level, top_level->core.x, top_level->core.y,
- header.pixmap_width, header.pixmap_height,
- top_level->core.border_width);
-
- resized = True;
- }
-
- image_width = header.pixmap_width;
- image_height = MAX_SAVE_IMAGE_SIZE / image_width;
- image_height = MIN(image_height, header.pixmap_height);
- image_size = PAD(image_width) * image_height;
-
- if ((image_data = malloc(image_size)) == NULL)
- {
- eprintf("Cannot malloc %d bytes\n", image_size);
- return (False);
- }
-
- image = XCreateImage(dpy, DefaultVisualOfScreen(screen),
- DefaultDepthOfScreen(screen), ZPixmap, 0, image_data,
- image_width, image_height, 32, 0);
-
- while (curr_y < w->core.height)
- {
- if (read(fd, image->data, image->bytes_per_line * image->height) < 0)
- {
- XDestroyImage(image);
- return (False);
- }
-
- XPutImage(dpy, w->canvas.pixmap, w->canvas.normal_gc, image,
- 0, 0, 0, curr_y, image_width, image_height);
-
- curr_y += image_height;
- if (curr_y + image_height > w->core.height)
- image->height = w->core.height - curr_y;
- }
- XDestroyImage(image);
-
- if (resized == False)
- /* slap the new pixmap up on the screen */
- CanvasRedisplay(widget, (XExposeEvent *) NULL, (Region) NULL);
-
- return (True);
- }
-
-
- Boolean CanvasSaveState(fd, widget)
- int fd;
- Widget widget;
- {
- CanvasWidget w = (CanvasWidget) widget;
- CanvasSaveStateStruct package;
- unsigned long swap_test = 1;
-
- package.width = (long) w->core.width;
- package.height = (long) w->core.height;
- package.task_x = (long) w->canvas.task_x;
- package.task_y = (long) w->canvas.task_y;
- package.limit = (long) w->canvas.curr_limit;
- package.finished = (long) w->canvas.finished;
- package.curr_task_width = (long) w->canvas.curr_task_width;
- package.curr_task_height = (long) w->canvas.curr_task_height;
-
- /* do the necessary swapping before laying in the strings */
- if (*(char *) &swap_test)
- ByteSwapLong((char *) &package, sizeof(CanvasSaveStateStruct));
-
- (void) sprintf(package.p_lo, "%.20G", w->canvas.p_lo);
- (void) sprintf(package.p_hi, "%.20G", w->canvas.p_hi);
- (void) sprintf(package.q_lo, "%.20G", w->canvas.q_lo);
- (void) sprintf(package.q_hi, "%.20G", w->canvas.q_hi);
- (void) sprintf(package.p_inc, "%.20G", w->canvas.p_inc);
- (void) sprintf(package.q_inc, "%.20G", w->canvas.q_inc);
-
- (void) write(fd, (char *) &package, sizeof(CanvasSaveStateStruct));
- return (True);
- }
-
-
- Boolean CanvasLoadState(fd, widget)
- int fd;
- Widget widget;
- {
- CanvasWidget w = (CanvasWidget) widget;
- CanvasSaveStateStruct package;
- unsigned long swap_test = 1;
- extern void SettingsSetLimit();
-
- (void) read(fd, (char *) &package, sizeof(CanvasSaveStateStruct));
-
- /* grab the strings before doing the necessary swapping */
- w->canvas.p_lo = atof(package.p_lo);
- w->canvas.p_hi = atof(package.p_hi);
- w->canvas.q_lo = atof(package.q_lo);
- w->canvas.q_hi = atof(package.q_hi);
- w->canvas.p_inc = atof(package.p_inc);
- w->canvas.q_inc = atof(package.q_inc);
-
- if (*(char *) &swap_test)
- ByteSwapLong((char *) &package, sizeof(CanvasSaveStateStruct));
-
- w->core.width = (Dimension) package.width;
- w->core.height = (Dimension) package.height;
- w->canvas.task_x = (short) package.task_x;
- w->canvas.task_y = (short) package.task_y;
- w->canvas.curr_limit = (short) package.limit;
- w->canvas.finished = (Boolean) package.finished;
-
- /* We don't need to save everything again unless we change something */
- w->canvas.needs_saving = False;
-
- /* Pause until told to restart drawing */
- w->canvas.paused = True;
-
- /* Update the current limit in the settings dialogbox */
- SettingsSetLimit((int) package.limit);
-
- CanvasChangeTaskSize(widget, (unsigned int) package.curr_task_width,
- (unsigned int) package.curr_task_height);
-
- return (True);
- }
-