Bitmap.c revision cbc4e2be
1/*
2
3Copyright 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29/*
30 * Author:  Davor Matic, MIT X Consortium
31 */
32
33#include <X11/IntrinsicP.h>
34#include <X11/StringDefs.h>
35#include <X11/Xaw/XawInit.h>
36#include <X11/Xmu/CharSet.h>
37#include <X11/Xmu/Drawing.h>
38#include <X11/Xatom.h>
39#include <X11/Xfuncs.h>
40#include <X11/Xos.h>
41#include "BitmapP.h"
42#include "Bitmap.h"
43
44#include <stdio.h>
45#include <math.h>
46
47#define min(x, y)                     ((((int)(x)) < (int)(y)) ? (x) : (y))
48#define max(x, y)                     ((((int)(x)) > (int)(y)) ? (x) : (y))
49
50Boolean DEBUG;
51
52#define DefaultGridTolerance 8
53#define DefaultBitmapSize    "16x16"
54#define FallbackBitmapWidth  16
55#define FallbackBitmapHeight 16
56#define DefaultGrid          TRUE
57#define DefaultDashed        TRUE
58#define DefaultStippled      TRUE
59#define DefaultProportional  TRUE
60#define DefaultAxes          FALSE
61#define DefaultMargin        16
62#define DefaultSquareWidth   16
63#define DefaultSquareHeight  16
64#define DefaultFilename      ""
65
66#define Offset(field) XtOffsetOf(BitmapRec, bitmap.field)
67
68static XtResource resources[] = {
69{XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
70     Offset(foreground_pixel), XtRString, XtDefaultForeground},
71{XtNhighlight, XtCHighlight, XtRPixel, sizeof(Pixel),
72     Offset(highlight_pixel), XtRString, XtDefaultForeground},
73{XtNframe, XtCFrame, XtRPixel, sizeof(Pixel),
74     Offset(frame_pixel), XtRString, XtDefaultForeground},
75{XtNgridTolerance, XtCGridTolerance, XtRDimension, sizeof(Dimension),
76     Offset(grid_tolerance), XtRImmediate, (XtPointer) DefaultGridTolerance},
77{XtNsize, XtCSize, XtRString, sizeof(String),
78     Offset(size), XtRImmediate, (XtPointer) DefaultBitmapSize},
79{XtNdashed, XtCDashed, XtRBoolean, sizeof(Boolean),
80     Offset(dashed), XtRImmediate, (XtPointer) DefaultDashed},
81{XtNgrid, XtCGrid, XtRBoolean, sizeof(Boolean),
82     Offset(grid), XtRImmediate, (XtPointer) DefaultGrid},
83{XtNstippled, XtCStippled, XtRBoolean, sizeof(Boolean),
84     Offset(stippled), XtRImmediate, (XtPointer) DefaultStippled},
85{XtNproportional, XtCProportional, XtRBoolean, sizeof(Boolean),
86     Offset(proportional), XtRImmediate, (XtPointer) DefaultProportional},
87{XtNaxes, XtCAxes, XtRBoolean, sizeof(Boolean),
88     Offset(axes), XtRImmediate, (XtPointer) DefaultAxes},
89{XtNsquareWidth, XtCSquareWidth, XtRDimension, sizeof(Dimension),
90     Offset(squareW), XtRImmediate, (XtPointer) DefaultSquareWidth},
91{XtNsquareHeight, XtCSquareHeight, XtRDimension, sizeof(Dimension),
92     Offset(squareH), XtRImmediate, (XtPointer) DefaultSquareHeight},
93{XtNmargin, XtCMargin, XtRDimension, sizeof(Dimension),
94     Offset(margin), XtRImmediate, (XtPointer) DefaultMargin},
95{XtNxHot, XtCXHot, XtRPosition, sizeof(Position),
96     Offset(hot.x), XtRImmediate, (XtPointer) NotSet},
97{XtNyHot, XtCYHot, XtRPosition, sizeof(Position),
98     Offset(hot.y), XtRImmediate, (XtPointer) NotSet},
99{XtNbutton1Function, XtCButton1Function, XtRButtonFunction, sizeof(int),
100     Offset(button_function[0]), XtRImmediate, (XtPointer) Set},
101{XtNbutton2Function, XtCButton2Function, XtRButtonFunction, sizeof(int),
102     Offset(button_function[1]), XtRImmediate, (XtPointer) Invert},
103{XtNbutton3Function, XtCButton3Function, XtRButtonFunction, sizeof(int),
104     Offset(button_function[2]), XtRImmediate, (XtPointer) Clear},
105{XtNbutton4Function, XtCButton4Function, XtRButtonFunction, sizeof(int),
106     Offset(button_function[3]), XtRImmediate, (XtPointer) Clear},
107{XtNbutton5Function, XtCButton5Function, XtRButtonFunction, sizeof(int),
108     Offset(button_function[4]), XtRImmediate, (XtPointer) Clear},
109{XtNfilename, XtCFilename, XtRString, sizeof(String),
110     Offset(filename), XtRImmediate, (XtPointer) DefaultFilename},
111{XtNbasename, XtCBasename, XtRString, sizeof(String),
112     Offset(basename), XtRImmediate, (XtPointer) DefaultFilename},
113{XtNdashes, XtCDashes, XtRBitmap, sizeof(Pixmap),
114     Offset(dashes), XtRImmediate, (XtPointer) XtUnspecifiedPixmap},
115{XtNstipple, XtCStipple, XtRBitmap, sizeof(Pixmap),
116     Offset(stipple), XtRImmediate, (XtPointer) XtUnspecifiedPixmap},
117};
118#undef Offset
119
120
121static XtActionsRec actions[] =
122{
123{"mark",               (XtActionProc)BWTMark},
124{"mark-all",           (XtActionProc)BWTMarkAll},
125{"unmark",             (XtActionProc)BWTUnmark},
126{"paste",              (XtActionProc)BWTPaste},
127{"bw-debug",           (XtActionProc)BWDebug},
128{"abort",              (XtActionProc)BWAbort},
129{"store-to-buffer",    (XtActionProc)BWStoreToBuffer},
130{"change-notify",      (XtActionProc)BWChangeNotify},
131{"set-changed",        (XtActionProc)BWSetChanged},
132{"up",                 (XtActionProc)BWUp},
133{"down",               (XtActionProc)BWDown},
134{"left",               (XtActionProc)BWLeft},
135{"right",              (XtActionProc)BWRight},
136{"fold",               (XtActionProc)BWFold},
137{"flip-horiz",         (XtActionProc)BWFlipHoriz},
138{"flip-vert",          (XtActionProc)BWFlipVert},
139{"rotate-right",       (XtActionProc)BWRotateRight},
140{"rotate-left",        (XtActionProc)BWRotateLeft},
141{"set",                (XtActionProc)BWSet},
142{"clear",              (XtActionProc)BWClear},
143{"invert",             (XtActionProc)BWInvert},
144{"undo",               (XtActionProc)BWUndo},
145{"redraw",             (XtActionProc)BWRedraw},
146};
147
148static char translations1[] =
149"\
150Shift<Btn1Down>: mark()\n\
151Shift<Btn2Down>: mark-all()\n\
152Shift<Btn3Down>: unmark()\n\
153Ctrl<BtnDown>:   paste()\n\
154Ctrl<Key>l: redraw()\n\
155<Key>d:     bw-debug()\n\
156<Key>a:     abort()\n\
157<Key>Up:    store-to-buffer()\
158            up()\
159            change-notify()\
160            set-changed()\n\
161<Key>KP_Up: store-to-buffer()\
162            up()\
163            change-notify()\
164            set-changed()\n\
165<Key>Down:  store-to-buffer()\
166            down()\
167            change-notify()\
168            set-changed()\n\
169<Key>KP_Down: store-to-buffer()\
170            down()\
171            change-notify()\
172            set-changed()\n\
173<Key>Left:  store-to-buffer()\
174            left()\
175            change-notify()\
176            set-changed()\n\
177<Key>KP_Left: store-to-buffer()\
178            left()\
179            change-notify()\
180            set-changed()\n\
181<Key>Right: store-to-buffer()\
182            right()\
183            change-notify()\
184            set-changed()\n\
185<Key>KP_Right: store-to-buffer()\
186            right()\
187            change-notify()\
188            set-changed()\n\
189<Key>f:     store-to-buffer()\
190            fold()\
191            change-notify()\
192            set-changed()\n\
193<Key>h:     store-to-buffer()\
194            flip-horiz()\
195            change-notify()\
196            set-changed()\n\
197";
198
199static char translations2[] =
200"<Key>v:     store-to-buffer()\
201            flip-vert()\
202            change-notify()\
203            set-changed()\n\
204<Key>r:     store-to-buffer()\
205            rotate-right()\
206            change-notify()\
207            set-changed()\n\
208<Key>l:     store-to-buffer()\
209            rotate-left()\
210            change-notify()\
211            set-changed()\n\
212<Key>s:     store-to-buffer()\
213            set()\
214            change-notify()\
215            set-changed()\n\
216<Key>c:     store-to-buffer()\
217            clear()\
218            change-notify()\
219            set-changed()\n\
220<Key>i:     store-to-buffer()\
221            invert()\
222            change-notify()\
223            set-changed()\n\
224<Key>u:     undo()\
225            change-notify()\
226            set-changed()\n\
227";
228
229static Atom targets[] = {
230    XA_BITMAP,
231    XA_PIXMAP
232};
233
234#include "Requests.h"
235
236
237static BWRequestRec requests[] =
238{
239{MarkRequest, sizeof(BWStatus),
240     TwoPointsEngage, (XtPointer) BWDrawRectangle,
241     TwoPointsTerminateTimed, (XtPointer) BWSelect,
242     NULL, (XtPointer) NULL},
243{RestoreRequest, sizeof(BWStatus),
244     OnePointEngage, (XtPointer) BWDragStored,
245     OnePointTerminate, (XtPointer) BWRestore,
246     NULL, (XtPointer) NULL},
247{ImmediateCopyRequest, sizeof(BWStatus),
248     OnePointEngage, (XtPointer) BWDragMarked,
249     OnePointTerminate, (XtPointer) BWCopy,
250     NULL, (XtPointer) NULL},
251{ImmediateMoveRequest, sizeof(BWStatus),
252     OnePointEngage, (XtPointer) BWDragMarked,
253     OnePointTerminate, (XtPointer) BWMove,
254     NULL, (XtPointer) NULL},
255{CopyRequest, sizeof(BWStatus),
256     DragOnePointEngage, (XtPointer) Paste,
257     DragOnePointTerminate, (XtPointer) ImmediateCopyRequest,
258     Interface, (XtPointer) BWUnmark},
259{MoveRequest, sizeof(BWStatus),
260     DragOnePointEngage, (XtPointer) Paste,
261     DragOnePointTerminate, (XtPointer) ImmediateMoveRequest,
262     Interface, (XtPointer) BWUnmark},
263{PointRequest, sizeof(BWStatus),
264     DragOnePointEngage, (XtPointer) BWDrawPoint,
265     DragOnePointTerminate, (XtPointer) BWDrawPoint,
266     NULL, (XtPointer) NULL},
267{CurveRequest, sizeof(BWStatus),
268     DragTwoPointsEngage, (XtPointer) BWBlindLine,
269     DragTwoPointsTerminate, (XtPointer) BWBlindLine,
270     NULL, (XtPointer) NULL},
271{LineRequest, sizeof(BWStatus),
272     TwoPointsEngage, (XtPointer) BWDrawLine,
273     TwoPointsTerminate, (XtPointer) BWDrawLine,
274     NULL, (XtPointer) NULL},
275{RectangleRequest, sizeof(BWStatus),
276     TwoPointsEngage, (XtPointer) BWDrawRectangle,
277     TwoPointsTerminate, (XtPointer) BWDrawRectangle,
278     NULL, (XtPointer) NULL},
279{FilledRectangleRequest, sizeof(BWStatus),
280     TwoPointsEngage, (XtPointer) BWDrawRectangle,
281     TwoPointsTerminate, (XtPointer) BWDrawFilledRectangle,
282     NULL, (XtPointer) NULL},
283{CircleRequest, sizeof(BWStatus),
284     TwoPointsEngage, (XtPointer) BWDrawCircle,
285     TwoPointsTerminate, (XtPointer) BWDrawCircle,
286     NULL, (XtPointer) NULL},
287{FilledCircleRequest, sizeof(BWStatus),
288     TwoPointsEngage, (XtPointer) BWDrawCircle,
289     TwoPointsTerminate, (XtPointer) BWDrawFilledCircle,
290     NULL, (XtPointer) NULL},
291{FloodFillRequest, sizeof(BWStatus),
292     OnePointEngage, (XtPointer) NULL,
293     OnePointTerminate, (XtPointer) BWFloodFill,
294     NULL, (XtPointer) NULL},
295{HotSpotRequest, sizeof(BWStatus),
296     OnePointEngage, (XtPointer) BWDrawHotSpot,
297     OnePointTerminate, (XtPointer) BWDrawHotSpot,
298     NULL, (XtPointer) NULL},
299{ZoomInRequest, sizeof(BWStatus),
300     TwoPointsEngage, (XtPointer) BWDrawRectangle,
301     TwoPointsTerminate, (XtPointer) BWZoomIn,
302     NULL, (XtPointer) NULL},
303};
304
305static void ClassInitialize(void);
306static void Initialize(Widget wrequest, Widget wnew,
307		       ArgList argv, Cardinal *argc);
308static void Redisplay(Widget w, XEvent *event, Region region);
309static void Resize(Widget w);
310static void Destroy(Widget w);
311static void Refresh(BitmapWidget BW, Position x, Position y,
312		    Dimension width, Dimension height);
313static Boolean SetValues(Widget old, Widget request, Widget new,
314			 ArgList args, Cardinal *num_args);
315
316BitmapClassRec bitmapClassRec = {
317{   /* core fields */
318    /* superclass		*/	(WidgetClass) &simpleClassRec,
319    /* class_name		*/	"Bitmap",
320    /* widget_size		*/	sizeof(BitmapRec),
321    /* class_initialize		*/	ClassInitialize,
322    /* class_part_initialize	*/	NULL,
323    /* class_inited		*/	FALSE,
324    /* initialize		*/	Initialize,
325    /* initialize_hook		*/	NULL,
326    /* realize			*/	XtInheritRealize,
327    /* actions			*/	actions,
328    /* num_actions		*/	XtNumber(actions),
329    /* resources		*/	resources,
330    /* num_resources		*/	XtNumber(resources),
331    /* xrm_class		*/	NULLQUARK,
332    /* compress_motion		*/	TRUE,
333    /* compress_exposure	*/	FALSE,
334    /* compress_enterleave	*/	TRUE,
335    /* visible_interest		*/	TRUE,
336    /* destroy			*/	Destroy,
337    /* resize			*/	Resize,
338    /* expose			*/	Redisplay,
339    /* set_values		*/	SetValues,
340    /* set_values_hook		*/	NULL,
341    /* set_values_almost	*/	XtInheritSetValuesAlmost,
342    /* get_values_hook		*/	NULL,
343    /* accept_focus		*/	NULL,
344    /* version			*/	XtVersion,
345    /* callback_private		*/	NULL,
346    /* tm_table			*/	NULL , /* set in code */
347    /* query_geometry		*/	XtInheritQueryGeometry,
348    /* display_accelerator	*/	XtInheritDisplayAccelerator,
349    /* extension		*/	NULL,
350  },
351  {
352    /* empty			*/	XtInheritChangeSensitive,
353  },
354  {
355    /* targets                  */      targets,
356    /* num_trets                */      XtNumber(targets),
357    /* requests                 */      requests,
358    /* num_requests             */      XtNumber(requests),
359  }
360};
361
362WidgetClass bitmapWidgetClass = (WidgetClass) &bitmapClassRec;
363
364/* ARGSUSED */
365
366void
367BWDebug(Widget w, XEvent *event, String *params, Cardinal *num_params)
368{
369    DEBUG ^= True;
370}
371
372Pixmap
373BWGetPixmap(Widget w)
374{
375    BitmapWidget BW = (BitmapWidget) w;
376
377    return GetPixmap(BW, BW->bitmap.zoom.image);
378}
379
380Pixmap
381BWGetUnzoomedPixmap(Widget w)
382{
383    BitmapWidget BW = (BitmapWidget) w;
384    GC gc;
385    Pixmap pix;
386
387    if (BW->bitmap.zooming) {
388	pix = XCreatePixmap(XtDisplay(w), XtWindow(w),
389			    BW->bitmap.zoom.image->width,
390			    BW->bitmap.zoom.image->height, 1);
391	if (!(gc = XCreateGC(XtDisplay(w), pix,
392			     (unsigned long) 0, (XGCValues *) 0))) {
393	    XFreePixmap(XtDisplay(w), pix);
394	    return (Pixmap) None;
395	}
396
397	XPutImage(XtDisplay(w), pix, gc,
398		  BW->bitmap.zoom.image,
399		  0, 0, 0, 0,
400		  BW->bitmap.zoom.image->width,
401		  BW->bitmap.zoom.image->height);
402	XPutImage(XtDisplay(w), pix, gc,
403		  BW->bitmap.image,
404		  0, 0,
405		  BW->bitmap.zoom.at_x,
406		  BW->bitmap.zoom.at_y,
407		  BW->bitmap.image->width,
408		  BW->bitmap.image->height);
409    }
410    else {
411	pix = XCreatePixmap(XtDisplay(w), XtWindow(w),
412			    BW->bitmap.image->width,
413			    BW->bitmap.image->height, 1);
414	if (! (gc = XCreateGC(XtDisplay(w), pix,
415			      (unsigned long) 0, (XGCValues *) 0))){
416	    XFreePixmap(XtDisplay(w), pix);
417	    return (Pixmap) None;
418	}
419
420	XPutImage(XtDisplay(w), pix, gc,
421		  BW->bitmap.image,
422		  0, 0, 0, 0,
423		  BW->bitmap.image->width,
424		  BW->bitmap.image->height);
425    }
426    XFreeGC(XtDisplay(w), gc);
427    return(pix);
428}
429
430
431XImage *
432GetImage(BitmapWidget BW, Pixmap pixmap)
433{
434    Window root;
435    int x, y;
436    unsigned int width, height, border_width, depth;
437    XImage *source, *image;
438
439    XGetGeometry(XtDisplay(BW), pixmap, &root, &x, &y,
440		 &width, &height, &border_width, &depth);
441
442    source = XGetImage(XtDisplay(BW), pixmap, x, y, width, height,
443		     1, XYPixmap);
444
445    image = ConvertToBitmapImage(BW, source);
446
447    return image;
448}
449
450XImage *
451CreateBitmapImage(BitmapWidget BW, char *data,
452		  Dimension width, Dimension height)
453{
454    XImage *image = XCreateImage(XtDisplay(BW),
455				 DefaultVisual(XtDisplay(BW),
456					       DefaultScreen(XtDisplay(BW))),
457				 1, XYBitmap, 0,
458				 data, width, height,
459				 8, ((int)width + 7) / 8);
460
461    image->height = height;
462    image->width = width;
463    image->depth = 1;
464    image->xoffset = 0;
465    image->format = XYBitmap;
466    image->data = (char *)data;
467    image->byte_order = LSBFirst;
468    image->bitmap_unit = 8;
469    image->bitmap_bit_order = LSBFirst;
470    image->bitmap_pad = 8;
471    image->bytes_per_line = ((int)width + 7) / 8;
472
473    return image;
474}
475
476void
477DestroyBitmapImage(XImage **image)
478{
479    /*XDestroyImage(*image);*/
480    if (image) {
481	if (*image) {
482	    if ((*image)->data)
483		XtFree((*image)->data);
484	    XtFree((char *)*image);
485	}
486	*image = NULL;
487    }
488}
489
490#if 0
491XImage *
492BWGetImage(Widget w, XEvent *event, String *params, Cardinal *num_params)
493{
494    BitmapWidget BW = (BitmapWidget) w;
495
496    return BW->bitmap.image;
497}
498#endif
499
500void
501BWChangeNotify(Widget w)
502{
503    BitmapWidget BW = (BitmapWidget) w;
504
505    if (BW->bitmap.notify)
506	(*BW->bitmap.notify)(w, NULL, NULL, NULL);
507}
508
509void
510BWNotify(Widget w, XtActionProc proc)
511{
512    BitmapWidget BW = (BitmapWidget) w;
513
514    BW->bitmap.notify = proc;
515}
516
517void
518BWSetChanged(Widget w)
519{
520    BitmapWidget BW = (BitmapWidget) w;
521
522    BW->bitmap.changed = True;
523}
524
525Boolean
526BWQueryChanged(Widget w)
527{
528    BitmapWidget BW = (BitmapWidget) w;
529
530    return BW->bitmap.changed;
531}
532
533void
534BWClearChanged(Widget w)
535{
536    BitmapWidget BW = (BitmapWidget) w;
537
538    BW->bitmap.changed = False;
539}
540
541Boolean
542BWQueryStored(Widget w)
543{
544    BitmapWidget BW = (BitmapWidget) w;
545
546    return (BW->bitmap.storage != NULL);
547}
548
549Boolean
550BWQueryStippled(Widget w)
551{
552    BitmapWidget BW = (BitmapWidget) w;
553
554    return BW->bitmap.stippled;
555}
556
557static void
558RedrawStippled(BitmapWidget BW)
559{
560  XExposeEvent event;
561
562  event.type = Expose;
563  event.display = XtDisplay((Widget)BW);
564  event.window = XtWindow((Widget)BW);
565  event.x = 0;
566  event.y = 0;
567  event.width = BW->core.width;
568  event.height = BW->core.height;
569  event.count = 0;
570
571  BWRedrawMark((Widget)BW);
572
573  BW->bitmap.stipple_change_expose_event = True;
574
575  XtDispatchEvent((XEvent *)&event);
576
577  BW->bitmap.stipple_change_expose_event = False;
578}
579
580void
581BWSwitchStippled(Widget w)
582{
583    BitmapWidget BW = (BitmapWidget) w;
584
585    RedrawStippled(BW);
586
587    BW->bitmap.stippled ^= True;
588    XSetFillStyle(XtDisplay(BW), BW->bitmap.highlighting_gc,
589		  (BW->bitmap.stippled ? FillStippled : FillSolid));
590
591    RedrawStippled(BW);
592}
593
594void
595BWSelect(Widget w, Position from_x, Position from_y,
596	 Position to_x, Position to_y, Time btime)
597{
598    BWMark(w, from_x, from_y, to_x, to_y);
599
600    BWGrabSelection(w, btime);
601}
602
603Boolean
604BWQueryAxes(Widget w)
605{
606    BitmapWidget BW = (BitmapWidget) w;
607
608    return BW->bitmap.axes;
609}
610
611void
612BWSwitchAxes(Widget w)
613{
614    BitmapWidget BW = (BitmapWidget) w;
615
616    BW->bitmap.axes ^= True;
617    BWHighlightAxes(w);
618}
619
620void
621BWAxes(Widget w, Boolean _switch)
622{
623    BitmapWidget BW = (BitmapWidget) w;
624
625    if (BW->bitmap.axes != _switch)
626	BWSwitchAxes(w);
627}
628
629void
630BWRedrawAxes(Widget w)
631{
632    BitmapWidget BW = (BitmapWidget) w;
633
634    if (BW->bitmap.axes)
635	BWHighlightAxes(w);
636}
637
638#if 0
639void
640BWPutImage(BitmapWidget w, Display *display, Drawable drawable, GC gc,
641	   Position x, Position y)
642{
643    BitmapWidget BW = (BitmapWidget) w;
644
645  XPutImage(display, drawable, gc, BW->bitmap.image,
646	    0, 0, x, y, BW->bitmap.image->width, BW->bitmap.image->height);
647}
648#endif
649
650static String
651StripFilename(_Xconst _XtString filename)
652{
653    const char *begin = strrchr(filename, '/');
654    const char *end;
655    char *result;
656    int length;
657
658    if (filename) {
659	begin = (begin ? begin + 1 : filename);
660	end = strchr(begin, '.'); /* change to strrchr to allow longer names */
661	length = (end ? (end - begin) : strlen (begin));
662	result = (char *) XtMalloc (length + 1);
663	strncpy (result, begin, length);
664	result [length] = '\0';
665	return (result);
666    }
667    else
668	return (NULL);
669}
670
671static int
672XmuWriteBitmapDataToFile(_Xconst _XtString filename,
673			 _Xconst _XtString basename,
674			 int width, int height, char *datap,
675			 int x_hot, int y_hot)
676{
677    FILE *file;
678    int i, data_length;
679
680    data_length = Length(width, height);
681
682    if(!filename || !strcmp(filename, "") || !strcmp(filename, "-")) {
683	file = stdout;
684	filename = "dummy";
685	}
686    else
687    	file = fopen(filename, "w+");
688
689    if (!basename || !strcmp(basename, "") || !strcmp(basename, "-"))
690	basename = StripFilename(filename);
691
692    if (file) {
693	fprintf(file, "#define %s_width %d\n", basename, width);
694	fprintf(file, "#define %s_height %d\n", basename, height);
695	if (QuerySet(x_hot, y_hot)) {
696	    fprintf(file, "#define %s_x_hot %d\n", basename, x_hot);
697	    fprintf(file, "#define %s_y_hot %d\n", basename, y_hot);
698	}
699	fprintf(file, "static unsigned char %s_bits[] = {\n   0x%02x",
700		basename, (unsigned char) datap[0]);
701	for(i = 1; i < data_length; i++) {
702	    fprintf(file, ",");
703	    fprintf(file, (i % 12) ? " " : "\n   ");
704	    fprintf(file, "0x%02x", (unsigned char) datap[i]);
705	}
706	fprintf(file, "};\n");
707
708	if (file != stdout)
709	    fclose(file);
710
711	return BitmapSuccess;
712    }
713
714    return 1;
715}
716
717/*
718 *
719 */
720
721				/* ARGSUSED */
722static void
723CvtStringToButtonFunction(XrmValuePtr args, /* not used */
724			  Cardinal *num_args, /* not used */
725			  XrmValuePtr from_val,
726			  XrmValuePtr to_val)
727{
728  static int button_function;
729  char lower_name[80];
730
731  XmuCopyISOLatin1Lowered (lower_name, (char*)from_val->addr);
732
733  if (!strcmp(lower_name, XtClear)) {
734    button_function = Clear;
735    to_val->addr = (XPointer) &button_function;
736    to_val->size = sizeof(button_function);
737    return;
738  }
739
740  if (!strcmp(lower_name, XtSet)) {
741    button_function = Set;
742    to_val->addr = (XPointer) &button_function;
743    to_val->size = sizeof(button_function);
744    return;
745  }
746
747  if (!strcmp(lower_name, XtInvert)) {
748    button_function = Invert;
749    to_val->addr = (XPointer) &button_function;
750    to_val->size = sizeof(button_function);
751    return;
752  }
753
754  XtStringConversionWarning(from_val->addr, XtRButtonFunction);
755  button_function = Clear;
756  to_val->addr = (XPointer) &button_function;
757  to_val->size = sizeof(button_function);
758
759}
760
761static void
762ClassInitialize(void)
763{
764  char *tm_table = XtMalloc(strlen(translations1) + strlen(translations2) + 1);
765  strcpy(tm_table, translations1);
766  strcat(tm_table, translations2);
767  bitmapClassRec.core_class.tm_table = tm_table;
768
769  XawInitializeWidgetSet();
770  XtAddConverter(XtRString, XtRButtonFunction, CvtStringToButtonFunction,
771		 NULL, 0);
772  DEBUG = False;
773}
774
775static void
776SetSizeFromSizeResource(BitmapWidget bw)
777{
778  if (BWParseSize(bw->bitmap.size,
779		  &bw->bitmap.width,
780		  &bw->bitmap.height)
781      ==
782      False) {
783    bw->bitmap.width = FallbackBitmapWidth;
784    bw->bitmap.height = FallbackBitmapHeight;
785    XtWarning("Cannot parse the size resource.  BitmapWidget");
786  }
787}
788
789
790/* ARGSUSED */
791static void
792Initialize(Widget wrequest, Widget wnew, ArgList argv, Cardinal *argc)
793{
794    BitmapWidget new = (BitmapWidget) wnew;
795
796    XGCValues  values;
797    XtGCMask   mask;
798    char *image_data, *buffer_data;
799
800    new->bitmap.stipple_change_expose_event = False;
801    new->bitmap.notify = NULL;
802    new->bitmap.cardinal = 0;
803    new->bitmap.current = 0;
804    new->bitmap.fold = False;
805    new->bitmap.changed = False;
806    new->bitmap.zooming = False;
807    new->bitmap.selection.own = False;
808    new->bitmap.selection.limbo = False;
809
810    new->bitmap.request_stack = (BWRequestStack *)
811	XtMalloc(sizeof(BWRequestStack));
812
813    new->bitmap.request_stack[0].request = NULL;
814    new->bitmap.request_stack[0].call_data = NULL;
815    new->bitmap.request_stack[0].trap = False;
816
817    SetSizeFromSizeResource(new);
818
819    new->core.width = new->bitmap.width * new->bitmap.squareW +
820	2 * new->bitmap.margin;
821    new->core.height = new->bitmap.height * new->bitmap.squareH +
822	2 * new->bitmap.margin;
823
824    new->bitmap.hot.x = new->bitmap.hot.y = NotSet;
825    new->bitmap.buffer_hot.x = new->bitmap.buffer_hot.y = NotSet;
826
827    new->bitmap.mark.from_x = new->bitmap.mark.from_y = NotSet;
828    new->bitmap.mark.to_x = new->bitmap.mark.to_y = NotSet;
829    new->bitmap.buffer_mark.from_x = new->bitmap.buffer_mark.from_y = NotSet;
830    new->bitmap.buffer_mark.to_x = new->bitmap.buffer_mark.to_y = NotSet;
831
832    values.foreground = new->bitmap.foreground_pixel;
833    values.background = new->core.background_pixel;
834    values.foreground ^= values.background;
835    values.function = GXxor;
836    mask = GCForeground | GCBackground | GCFunction;
837    new->bitmap.drawing_gc = XCreateGC(XtDisplay(new),
838				       RootWindow(XtDisplay(new),
839				       DefaultScreen(XtDisplay(new))),
840				       mask, &values);
841
842    values.foreground = new->bitmap.highlight_pixel;
843    values.background = new->core.background_pixel;
844    values.foreground ^= values.background;
845    values.function = GXxor;
846    mask = GCForeground | GCBackground | GCFunction;
847    if (new->bitmap.stipple != XtUnspecifiedPixmap)
848    {
849	values.stipple = new->bitmap.stipple;
850	mask |= GCStipple | GCFillStyle;
851    }
852    values.fill_style = (new->bitmap.stippled ? FillStippled : FillSolid);
853
854    new->bitmap.highlighting_gc = XCreateGC(XtDisplay(new),
855					    RootWindow(XtDisplay(new),
856					       DefaultScreen(XtDisplay(new))),
857					    mask, &values);
858
859
860    values.foreground = new->bitmap.frame_pixel;
861    values.background = new->core.background_pixel;
862    values.foreground ^= values.background;
863    mask = GCForeground | GCBackground | GCFunction;
864    if (new->bitmap.dashes != XtUnspecifiedPixmap)
865    {
866	values.stipple = new->bitmap.dashes;
867	mask |= GCStipple | GCFillStyle;
868    }
869    values.fill_style = (new->bitmap.dashed ? FillStippled : FillSolid);
870
871    new->bitmap.frame_gc = XCreateGC(XtDisplay(new),
872				     RootWindow(XtDisplay(new),
873						DefaultScreen(XtDisplay(new))),
874				     mask, &values);
875
876    values.foreground = new->bitmap.highlight_pixel;
877    values.background = new->core.background_pixel;
878    values.foreground ^= values.background;
879    mask = GCForeground | GCBackground | GCFunction;
880    new->bitmap.axes_gc = XCreateGC(XtDisplay(new),
881				     RootWindow(XtDisplay(new),
882						DefaultScreen(XtDisplay(new))),
883				     mask, &values);
884
885    image_data = CreateCleanData(Length(new->bitmap.width,
886					new->bitmap.height));
887    buffer_data = CreateCleanData(Length(new->bitmap.width,
888					 new->bitmap.height));
889
890    new->bitmap.storage = NULL;
891
892    new->bitmap.image = CreateBitmapImage(new,
893					  image_data,
894					  new->bitmap.width,
895					  new->bitmap.height);
896    new->bitmap.buffer = CreateBitmapImage(new,
897					   buffer_data,
898					   new->bitmap.width,
899					   new->bitmap.height);
900
901    /* Read file */
902    {
903	int status;
904	XImage *image, *buffer;
905	unsigned char *image_data;
906	char *buffer_data;
907	unsigned int width, height;
908	int x_hot, y_hot;
909
910	status = XmuReadBitmapDataFromFile(new->bitmap.filename,
911					   &width, &height, &image_data,
912					   &x_hot, &y_hot);
913	if (status == BitmapSuccess) {
914
915	    buffer_data = CreateCleanData(Length(width, height));
916
917	    image = CreateBitmapImage(new, (char *)image_data, width, height);
918	    buffer = CreateBitmapImage(new, buffer_data, width, height);
919
920	    TransferImageData(new->bitmap.image, buffer);
921
922	    DestroyBitmapImage(&new->bitmap.image);
923	    DestroyBitmapImage(&new->bitmap.buffer);
924
925	    new->bitmap.image = image;
926	    new->bitmap.buffer = buffer;
927	    new->bitmap.width = width;
928	    new->bitmap.height = height;
929
930	    new->bitmap.hot.x = x_hot;
931	    new->bitmap.hot.y = y_hot;
932
933	    new->bitmap.changed = False;
934	    new->bitmap.zooming = False;
935	}
936
937	new->bitmap.filename = XtNewString(new->bitmap.filename);
938
939	if (!strcmp(new->bitmap.basename, "")) {
940	    new->bitmap.basename = StripFilename(new->bitmap.filename);
941	}
942	else
943	  new->bitmap.basename = XtNewString(new->bitmap.basename);
944    }
945
946    Resize((Widget)new);
947}
948
949
950/* returns False if the format is wrong */
951Boolean
952BWParseSize(String size, Dimension *width, Dimension *height)
953{
954  int x, y;
955  unsigned int w, h;
956  int status;
957
958  status = XParseGeometry(size, &x, &y, &w, &h);
959
960  if (status & (WidthValue | HeightValue)) {
961    *width = (Dimension) w;
962    *height = (Dimension) h;
963    return True;
964  }
965  else return False;
966
967}
968
969
970Boolean
971BWQueryMarked(Widget w)
972{
973    BitmapWidget BW = (BitmapWidget) w;
974
975    return QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y);
976}
977
978static void
979FixMark(BitmapWidget BW)
980{
981    if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
982	BW->bitmap.mark.from_x = min(BW->bitmap.mark.from_x,
983				     BW->bitmap.image->width);
984	BW->bitmap.mark.from_y = min(BW->bitmap.mark.from_y,
985				     BW->bitmap.image->height);
986	BW->bitmap.mark.to_x = min(BW->bitmap.mark.to_x,
987				   BW->bitmap.image->width);
988	BW->bitmap.mark.to_y = min(BW->bitmap.mark.to_y,
989				   BW->bitmap.image->height);
990
991	if((BW->bitmap.mark.from_x == BW->bitmap.mark.from_y) &&
992	   (BW->bitmap.mark.to_x   == BW->bitmap.mark.to_y))
993	    BW->bitmap.mark.from_x =
994		BW->bitmap.mark.from_y =
995		    BW->bitmap.mark.to_x =
996			BW->bitmap.mark.to_y = NotSet;
997    }
998}
999
1000/* ARGSUSED */
1001int
1002BWStoreFile(Widget w, _Xconst _XtString filename, _Xconst _XtString *basename)
1003{
1004    BitmapWidget BW = (BitmapWidget) w;
1005    int status;
1006    unsigned char *storage_data;
1007    unsigned int width, height;
1008    int x_hot, y_hot;
1009
1010    status = XmuReadBitmapDataFromFile(filename, &width, &height,
1011				       &storage_data, &x_hot, &y_hot);
1012    if (status == BitmapSuccess) {
1013
1014	DestroyBitmapImage(&BW->bitmap.storage);
1015
1016	BW->bitmap.storage = CreateBitmapImage(BW, (char *)storage_data, width, height);
1017
1018	return BitmapSuccess;
1019    }
1020    else
1021	XtWarning(" read file failed.  BitmapWidget");
1022
1023    return status;
1024}
1025
1026String
1027BWUnparseStatus(Widget w)
1028{
1029    BitmapWidget BW = (BitmapWidget) w;
1030
1031    snprintf(BW->bitmap.status, sizeof(BW->bitmap.status),
1032	    "Filename: %s  Basename: %s  Size: %dx%d",
1033	    (strcmp(BW->bitmap.filename, "") ? BW->bitmap.filename : "<none>"),
1034	    (strcmp(BW->bitmap.basename, "") ? BW->bitmap.basename : "<none>"),
1035	    BW->bitmap.width, BW->bitmap.height);
1036
1037    return BW->bitmap.status;
1038}
1039
1040void
1041BWChangeFilename(Widget w, _Xconst _XtString str)
1042{
1043  BitmapWidget BW = (BitmapWidget) w;
1044
1045  if (str) {
1046    XtFree(BW->bitmap.filename);
1047    BW->bitmap.filename = XtNewString( str);
1048  }
1049}
1050
1051void
1052BWChangeBasename(Widget w, _Xconst _XtString str)
1053{
1054  BitmapWidget BW = (BitmapWidget) w;
1055
1056  if (str) {
1057    XtFree(BW->bitmap.basename);
1058    BW->bitmap.basename = XtNewString(str);
1059  }
1060}
1061
1062
1063int
1064BWReadFile(Widget w, _Xconst _XtString filename, _Xconst _XtString basename) /* ARGSUSED */
1065{
1066    BitmapWidget BW = (BitmapWidget) w;
1067    int status;
1068    XImage *image, *buffer;
1069    unsigned char *image_data;
1070    char *buffer_data;
1071    unsigned int width, height;
1072    int x_hot, y_hot;
1073
1074    if (!filename)
1075	filename = BW->bitmap.filename;
1076
1077    status = XmuReadBitmapDataFromFile(filename, &width, &height, &image_data,
1078				       &x_hot, &y_hot);
1079    if (status == BitmapSuccess) {
1080
1081	buffer_data = CreateCleanData(Length(width, height));
1082
1083	image = CreateBitmapImage(BW, (char *)image_data, width, height);
1084	buffer = CreateBitmapImage(BW, buffer_data, width, height);
1085
1086	TransferImageData(BW->bitmap.image, buffer);
1087
1088	DestroyBitmapImage(&BW->bitmap.image);
1089	DestroyBitmapImage(&BW->bitmap.buffer);
1090
1091	BW->bitmap.image = image;
1092	BW->bitmap.buffer = buffer;
1093	BW->bitmap.width = width;
1094	BW->bitmap.height = height;
1095
1096	BW->bitmap.hot.x = x_hot;
1097	BW->bitmap.hot.y = y_hot;
1098
1099	BW->bitmap.changed = False;
1100	BW->bitmap.zooming = False;
1101
1102	XtFree(BW->bitmap.filename);
1103	BW->bitmap.filename = XtNewString(filename);
1104	XtFree(BW->bitmap.basename);
1105	BW->bitmap.basename= XtNewString(StripFilename(filename));
1106
1107	BWUnmark(w);
1108
1109	Resize((Widget)BW);
1110
1111	if (BW->core.visible) {
1112	    XClearArea(XtDisplay(BW), XtWindow(BW),
1113		       0, 0,
1114		       BW->core.width, BW->core.height,
1115		       True);
1116	}
1117
1118	return BitmapSuccess;
1119    }
1120    else
1121	XtWarning(" read file failed.  BitmapWidget");
1122
1123    return status;
1124}
1125
1126#if 0
1127void
1128BWSetImage(Widget w, XImage *image)
1129{
1130    BitmapWidget BW = (BitmapWidget) w;
1131    XImage *buffer;
1132    char *buffer_data;
1133
1134    buffer_data = CreateCleanData(Length(image->width, image->height));
1135    buffer = CreateBitmapImage(BW, buffer_data,
1136			       (Dimension) image->width,
1137			       (Dimension) image->height);
1138
1139    TransferImageData(BW->bitmap.image, buffer);
1140
1141    DestroyBitmapImage(&BW->bitmap.image);
1142    DestroyBitmapImage(&BW->bitmap.buffer);
1143
1144    BW->bitmap.image = image;
1145    BW->bitmap.buffer = buffer;
1146    BW->bitmap.width = image->width;
1147    BW->bitmap.height = image->height;
1148
1149    Resize((Widget)BW);
1150
1151    if (BW->core.visible) {
1152	XClearArea(XtDisplay(BW), XtWindow(BW),
1153		   0, 0,
1154		   BW->core.width, BW->core.height,
1155		   True);
1156    }
1157}
1158#endif
1159
1160int
1161BWWriteFile(Widget w, _Xconst _XtString filename, _Xconst _XtString basename)
1162{
1163    BitmapWidget BW = (BitmapWidget) w;
1164    char *data;
1165    XImage *image;
1166    XPoint hot;
1167    int status;
1168
1169    if (BW->bitmap.zooming) {
1170        data = XtMalloc(Length(BW->bitmap.zoom.image->width,
1171			       BW->bitmap.zoom.image->height));
1172	memmove( data, BW->bitmap.zoom.image->data,
1173	      Length(BW->bitmap.zoom.image->width,
1174		     BW->bitmap.zoom.image->height));
1175	image = CreateBitmapImage(BW, data,
1176				  (Dimension) BW->bitmap.zoom.image->width,
1177				  (Dimension) BW->bitmap.zoom.image->height);
1178	CopyImageData(BW->bitmap.image, image,
1179		      0, 0,
1180		      BW->bitmap.image->width - 1,
1181		      BW->bitmap.image->height - 1,
1182		      BW->bitmap.zoom.at_x, BW->bitmap.zoom.at_y);
1183
1184	if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)) {
1185	    hot.x = BW->bitmap.hot.x + BW->bitmap.zoom.at_x;
1186	    hot.y = BW->bitmap.hot.y + BW->bitmap.zoom.at_y;
1187	}
1188	else
1189	    hot = BW->bitmap.zoom.hot;
1190    }
1191    else {
1192	image = BW->bitmap.image;
1193	hot = BW->bitmap.hot;
1194    }
1195
1196    if (!filename) filename = BW->bitmap.filename;
1197    else {
1198	XtFree(BW->bitmap.filename);
1199	BW->bitmap.filename = XtNewString(filename);
1200	XtFree(BW->bitmap.basename);
1201	BW->bitmap.basename= XtNewString(StripFilename(filename));
1202    }
1203    if (!basename) basename = BW->bitmap.basename;
1204    else {
1205	XtFree(BW->bitmap.basename);
1206	BW->bitmap.basename = XtNewString(basename);
1207    }
1208
1209    if (DEBUG)
1210	fprintf(stderr, "Saving filename: %s %s\n", filename, basename);
1211
1212    status = XmuWriteBitmapDataToFile(filename, basename,
1213				      image->width, image->height, image->data,
1214				      hot.x, hot.y);
1215    if (BW->bitmap.zooming)
1216	DestroyBitmapImage(&image);
1217
1218    if (status == BitmapSuccess)
1219	BW->bitmap.changed = False;
1220
1221    return status;
1222}
1223
1224String
1225BWGetFilename(Widget w, String *str)
1226{
1227    BitmapWidget BW = (BitmapWidget) w;
1228
1229    *str = XtNewString(BW->bitmap.filename);
1230
1231    return *str;
1232}
1233
1234String
1235BWGetFilepath(Widget w, String *str)
1236{
1237    BitmapWidget BW = (BitmapWidget) w;
1238    String end;
1239
1240    *str = XtNewString(BW->bitmap.filename);
1241    end = strrchr(*str, '/');
1242
1243    if (end)
1244	*(end + 1) = '\0';
1245    else
1246	**str = '\0';
1247
1248    return *str;
1249}
1250
1251
1252String
1253BWGetBasename(Widget w, String *str)
1254{
1255    BitmapWidget BW = (BitmapWidget) w;
1256
1257    *str = XtNewString(BW->bitmap.basename);
1258
1259    return *str;
1260}
1261
1262static void
1263FixHotSpot(BitmapWidget BW)
1264{
1265    if (!QueryInBitmap(BW, BW->bitmap.hot.x, BW->bitmap.hot.y))
1266	BW->bitmap.hot.x = BW->bitmap.hot.y = NotSet;
1267}
1268
1269static void
1270ZoomOut(BitmapWidget BW)
1271{
1272    CopyImageData(BW->bitmap.image, BW->bitmap.zoom.image,
1273		  0, 0,
1274		  BW->bitmap.image->width - 1,
1275		  BW->bitmap.image->height - 1,
1276		  BW->bitmap.zoom.at_x, BW->bitmap.zoom.at_y);
1277
1278    DestroyBitmapImage(&BW->bitmap.image);
1279    DestroyBitmapImage(&BW->bitmap.buffer);
1280
1281    BW->bitmap.image = BW->bitmap.zoom.image;
1282    BW->bitmap.buffer = BW->bitmap.zoom.buffer;
1283    BW->bitmap.width = BW->bitmap.image->width;
1284    BW->bitmap.height = BW->bitmap.image->height;
1285    BW->bitmap.fold = BW->bitmap.zoom.fold;
1286    BW->bitmap.changed |= BW->bitmap.zoom.changed;
1287    BW->bitmap.grid = BW->bitmap.zoom.grid;
1288
1289    if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)) {
1290	BW->bitmap.hot.x += BW->bitmap.zoom.at_x;
1291	BW->bitmap.hot.y += BW->bitmap.zoom.at_y;
1292    }
1293    else
1294	BW->bitmap.hot = BW->bitmap.zoom.hot;
1295
1296    BW->bitmap.mark.from_x = NotSet;
1297    BW->bitmap.mark.from_y = NotSet;
1298    BW->bitmap.mark.to_x = NotSet;
1299    BW->bitmap.mark.to_y = NotSet;
1300    BW->bitmap.zooming = False;
1301}
1302
1303void
1304BWZoomOut(Widget w)
1305{
1306    BitmapWidget BW = (BitmapWidget) w;
1307
1308    if (BW->bitmap.zooming) {
1309	ZoomOut(BW);
1310
1311	Resize((Widget)BW);
1312	if (BW->core.visible)
1313	    XClearArea(XtDisplay(BW), XtWindow(BW),
1314		       0, 0,
1315		       BW->core.width, BW->core.height,
1316		       True);
1317    }
1318}
1319
1320
1321void
1322BWZoomMarked(Widget w)
1323{
1324    BitmapWidget BW = (BitmapWidget) w;
1325
1326    BWZoomIn(w,
1327	     BW->bitmap.mark.from_x, BW->bitmap.mark.from_y,
1328	     BW->bitmap.mark.to_x,   BW->bitmap.mark.to_y);
1329}
1330
1331void
1332BWZoomIn(Widget w,
1333	 Position from_x, Position from_y,
1334	 Position to_x, Position to_y)
1335{
1336    BitmapWidget BW = (BitmapWidget) w;
1337    XImage *image, *buffer;
1338    Dimension width, height;
1339    char *image_data, *buffer_data;
1340
1341    if (BW->bitmap.zooming)
1342	ZoomOut(BW);
1343
1344    QuerySwap(from_x, to_x);
1345    QuerySwap(from_y, to_y);
1346    from_x = max(0, from_x);
1347    from_y = max(0, from_y);
1348    to_x = min(BW->bitmap.width - 1, to_x);
1349    to_y = min(BW->bitmap.height - 1, to_y);
1350
1351    width = to_x - from_x + 1;
1352    height = to_y - from_y + 1;
1353
1354    image_data = CreateCleanData(Length(width, height));
1355    buffer_data = CreateCleanData(Length(width, height));
1356
1357    image = CreateBitmapImage(BW, image_data, width, height);
1358    buffer = CreateBitmapImage(BW, buffer_data, width, height);
1359
1360    CopyImageData(BW->bitmap.image, image, from_x, from_y, to_x, to_y, 0, 0);
1361    CopyImageData(BW->bitmap.buffer, buffer, from_x, from_y, to_x, to_y, 0, 0);
1362
1363    BW->bitmap.zoom.image = BW->bitmap.image;
1364    BW->bitmap.zoom.buffer = BW->bitmap.buffer;
1365    BW->bitmap.zoom.at_x = from_x;
1366    BW->bitmap.zoom.at_y = from_y;
1367    BW->bitmap.zoom.fold = BW->bitmap.fold;
1368    BW->bitmap.zoom.changed = BW->bitmap.changed;
1369    BW->bitmap.zoom.hot = BW->bitmap.hot;
1370    BW->bitmap.zoom.grid = BW->bitmap.grid;
1371
1372    BW->bitmap.image = image;
1373    BW->bitmap.buffer = buffer;
1374    BW->bitmap.width = width;
1375    BW->bitmap.height = height;
1376    BW->bitmap.changed = False;
1377    BW->bitmap.hot.x -= from_x;
1378    BW->bitmap.hot.y -= from_y;
1379    BW->bitmap.mark.from_x = NotSet;
1380    BW->bitmap.mark.from_y = NotSet;
1381    BW->bitmap.mark.to_x = NotSet;
1382    BW->bitmap.mark.to_y = NotSet;
1383    BW->bitmap.zooming = True;
1384    BW->bitmap.grid = True; /* potencially true, could use a resource here */
1385
1386    FixHotSpot(BW);
1387
1388    Resize((Widget)BW);
1389    if (BW->core.visible)
1390	XClearArea(XtDisplay(BW), XtWindow(BW),
1391		   0, 0,
1392		   BW->core.width, BW->core.height,
1393		   True);
1394}
1395
1396
1397void
1398BWRescale(Widget w, Dimension width, Dimension height)
1399{
1400    BitmapWidget BW = (BitmapWidget) w;
1401    XImage *image, *buffer;
1402    char *buffer_data;
1403
1404    if (BW->bitmap.zooming)
1405	ZoomOut(BW);
1406
1407    image = ScaleBitmapImage(BW, BW->bitmap.image,
1408		       (double) width / (double) BW->bitmap.image->width,
1409		       (double) height / (double) BW->bitmap.image->height);
1410
1411    buffer_data = CreateCleanData(Length(image->width, image->height));
1412    buffer = CreateBitmapImage(BW, buffer_data,
1413			       (Dimension) image->width,
1414			       (Dimension) image->height);
1415
1416    TransferImageData(BW->bitmap.buffer, buffer);
1417
1418    DestroyBitmapImage(&BW->bitmap.image);
1419    DestroyBitmapImage(&BW->bitmap.buffer);
1420
1421    BW->bitmap.image = image;
1422    BW->bitmap.buffer = buffer;
1423    BW->bitmap.width = image->width;
1424    BW->bitmap.height = image->height;
1425
1426    FixHotSpot(BW);
1427    FixMark(BW);
1428
1429    Resize((Widget)BW);
1430    if (BW->core.visible)
1431	XClearArea(XtDisplay(BW), XtWindow(BW),
1432		   0, 0,
1433		   BW->core.width, BW->core.height,
1434		   True);
1435}
1436
1437Boolean
1438BWQueryZooming(Widget w)
1439{
1440    BitmapWidget BW = (BitmapWidget) w;
1441
1442    return BW->bitmap.zooming;
1443}
1444
1445
1446static void
1447ResizeGrid(BitmapWidget BW, Dimension width, Dimension height)
1448{
1449  XImage *image, *buffer;
1450  char *image_data, *buffer_data;
1451
1452  if (BW->bitmap.zooming)
1453    ZoomOut(BW);
1454
1455  image_data = CreateCleanData(Length(width, height));
1456  buffer_data = CreateCleanData(Length(width, height));
1457
1458  image = CreateBitmapImage(BW, image_data, width, height);
1459  buffer = CreateBitmapImage(BW, buffer_data, width, height);
1460
1461  TransferImageData(BW->bitmap.image, image);
1462  TransferImageData(BW->bitmap.buffer, buffer);
1463
1464  DestroyBitmapImage(&BW->bitmap.image);
1465  DestroyBitmapImage(&BW->bitmap.buffer);
1466
1467  BW->bitmap.image = image;
1468  BW->bitmap.buffer = buffer;
1469  BW->bitmap.width = width;
1470  BW->bitmap.height = height;
1471
1472  FixHotSpot(BW);
1473  FixMark(BW);
1474}
1475
1476void
1477BWResize(Widget w, Dimension width, Dimension height)
1478{
1479    BitmapWidget BW = (BitmapWidget) w;
1480
1481    ResizeGrid(BW, width, height);
1482
1483    Resize((Widget)BW);
1484    if (BW->core.visible)
1485	XClearArea(XtDisplay(BW), XtWindow(BW),
1486		   0, 0,
1487		   BW->core.width, BW->core.height,
1488		   True);
1489}
1490
1491static void
1492Destroy(Widget w)
1493{
1494    BitmapWidget BW = (BitmapWidget) w;
1495
1496    XFreeGC(XtDisplay(w), BW->bitmap.drawing_gc);
1497    XFreeGC(XtDisplay(w), BW->bitmap.highlighting_gc);
1498    XFreeGC(XtDisplay(w), BW->bitmap.frame_gc);
1499    XFreeGC(XtDisplay(w), BW->bitmap.axes_gc);
1500    BWRemoveAllRequests(w);
1501
1502    XtFree(BW->bitmap.filename);
1503    XtFree(BW->bitmap.basename);
1504}
1505
1506
1507static void
1508Resize(Widget w)
1509{
1510    BitmapWidget BW = (BitmapWidget) w;
1511
1512    Dimension squareW, squareH;
1513
1514    squareW = max(1, ((int)BW->core.width - 2 * (int)BW->bitmap.margin) /
1515		  (int)BW->bitmap.width);
1516    squareH = max(1, ((int)BW->core.height - 2 * (int)BW->bitmap.margin) /
1517		  (int)BW->bitmap.height);
1518
1519    if (BW->bitmap.proportional)
1520	BW->bitmap.squareW = BW->bitmap.squareH = min(squareW, squareH);
1521    else {
1522	BW->bitmap.squareW = squareW;
1523	BW->bitmap.squareH = squareH;
1524    }
1525
1526    BW->bitmap.horizOffset = max((Position)BW->bitmap.margin,
1527				 (Position)(BW->core.width -
1528					    BW->bitmap.width *
1529					    BW->bitmap.squareW) / 2);
1530    BW->bitmap.vertOffset = max((Position)BW->bitmap.margin,
1531				(Position)(BW->core.height -
1532					   BW->bitmap.height *
1533					   BW->bitmap.squareH) / 2);
1534
1535    BW->bitmap.grid &= ((BW->bitmap.squareW > BW->bitmap.grid_tolerance) &&
1536			(BW->bitmap.squareH > BW->bitmap.grid_tolerance));
1537}
1538
1539/* ARGSUSED */
1540static void
1541Redisplay(Widget w, XEvent *event, Region region)
1542{
1543     BitmapWidget BW = (BitmapWidget) w;
1544
1545  if(event->type == Expose
1546     &&
1547     BW->core.visible)
1548    if (BW->bitmap.stipple_change_expose_event == False)
1549      Refresh(BW,
1550	      event->xexpose.x, event->xexpose.y,
1551	      event->xexpose.width, event->xexpose.height);
1552}
1553
1554void
1555BWClip(Widget w, Position x, Position y, Dimension width, Dimension height)
1556{
1557    Position      from_x, from_y,
1558                  to_x, to_y;
1559    BitmapWidget BW = (BitmapWidget) w;
1560    XRectangle rectangle;
1561
1562    from_x = InBitmapX(BW, x);
1563    from_y = InBitmapY(BW, y);
1564    to_x = InBitmapX(BW, x + width);
1565    to_y = InBitmapY(BW, y + height);
1566    QuerySwap(from_x, to_x);
1567    QuerySwap(from_y, to_y);
1568    from_x = max(0, from_x);
1569    from_y = max(0, from_y);
1570    to_x = min(BW->bitmap.width - 1, to_x);
1571    to_y = min(BW->bitmap.height - 1, to_y);
1572
1573    rectangle.x = InWindowX(BW, from_x);
1574    rectangle.y = InWindowY(BW, from_y);
1575    rectangle.width = InWindowX(BW, to_x  + 1) - InWindowX(BW, from_x);
1576    rectangle.height = InWindowY(BW, to_y + 1) - InWindowY(BW, from_y);
1577    XSetClipRectangles(XtDisplay(BW),
1578		       BW->bitmap.highlighting_gc,
1579		       0, 0,
1580		       &rectangle, 1,
1581		       Unsorted);
1582    XSetClipRectangles(XtDisplay(BW),
1583		       BW->bitmap.drawing_gc,
1584		       0, 0,
1585		       &rectangle, 1,
1586		       Unsorted);
1587    XSetClipRectangles(XtDisplay(BW),
1588		       BW->bitmap.frame_gc,
1589		       0, 0,
1590		       &rectangle, 1,
1591		       Unsorted);
1592    XSetClipRectangles(XtDisplay(BW),
1593		       BW->bitmap.axes_gc,
1594		       0, 0,
1595		       &rectangle, 1,
1596		       Unsorted);
1597}
1598
1599void
1600BWUnclip(Widget w)
1601{
1602    BitmapWidget BW = (BitmapWidget) w;
1603    XRectangle rectangle;
1604
1605    rectangle.x = InWindowX(BW, 0);
1606    rectangle.y = InWindowY(BW, 0);
1607    rectangle.width = InWindowX(BW, BW->bitmap.width) - InWindowX(BW, 0);
1608    rectangle.height = InWindowY(BW, BW->bitmap.height) - InWindowY(BW, 0);
1609    XSetClipRectangles(XtDisplay(BW),
1610		       BW->bitmap.highlighting_gc,
1611		       0, 0,
1612		       &rectangle, 1,
1613		       Unsorted);
1614    XSetClipRectangles(XtDisplay(BW),
1615		       BW->bitmap.drawing_gc,
1616		       0, 0,
1617		       &rectangle, 1,
1618		       Unsorted);
1619    XSetClipRectangles(XtDisplay(BW),
1620		       BW->bitmap.frame_gc,
1621		       0, 0,
1622		       &rectangle, 1,
1623		       Unsorted);
1624    XSetClipRectangles(XtDisplay(BW),
1625		       BW->bitmap.axes_gc,
1626		       0, 0,
1627		       &rectangle, 1,
1628		       Unsorted);
1629}
1630
1631static void
1632Refresh(BitmapWidget BW, Position x, Position y,
1633	Dimension width, Dimension height)
1634{
1635    XRectangle rectangle;
1636
1637    rectangle.x = min(x, InWindowX(BW, InBitmapX(BW, x)));
1638    rectangle.y = min(y, InWindowY(BW, InBitmapY(BW, y)));
1639    rectangle.width = max(x + width,
1640		     InWindowX(BW, InBitmapX(BW, x + width)+1)) - rectangle.x;
1641    rectangle.height = max(y + height,
1642		     InWindowY(BW, InBitmapY(BW, y + height)+1)) - rectangle.y;
1643
1644    XClearArea(XtDisplay(BW), XtWindow(BW),
1645	       rectangle.x, rectangle.y,
1646	       rectangle.width, rectangle.height,
1647	       False);
1648
1649    XSetClipRectangles(XtDisplay(BW),
1650		       BW->bitmap.frame_gc,
1651		       0, 0,
1652		       &rectangle, 1,
1653		       Unsorted);
1654
1655    XDrawRectangle(XtDisplay(BW), XtWindow(BW),
1656		   BW->bitmap.frame_gc,
1657		   InWindowX(BW, 0) - 1, InWindowY(BW, 0) - 1,
1658		   InWindowX(BW, BW->bitmap.width) - InWindowX(BW, 0) + 1,
1659		   InWindowY(BW, BW->bitmap.height) - InWindowY(BW, 0) + 1);
1660
1661    BWClip((Widget) BW, x, y, width, height);
1662
1663    BWRedrawGrid((Widget) BW, x, y, width, height);
1664
1665    BWRedrawSquares((Widget) BW, x, y, width, height);
1666
1667    BWRedrawMark((Widget) BW);
1668    BWRedrawHotSpot((Widget) BW);
1669    BWRedrawAxes((Widget) BW);
1670    BWUnclip((Widget) BW);
1671}
1672
1673Boolean
1674BWQueryGrid(Widget w)
1675{
1676    BitmapWidget BW = (BitmapWidget) w;
1677
1678    return BW->bitmap.grid;
1679}
1680
1681void
1682BWSwitchGrid(Widget w)
1683{
1684    BitmapWidget BW = (BitmapWidget) w;
1685    BW->bitmap.grid ^= TRUE;
1686    BWDrawGrid(w,
1687	       0, 0,
1688	       BW->bitmap.image->width - 1, BW->bitmap.image->height - 1);
1689}
1690
1691void
1692BWGrid(Widget w, Boolean _switch)
1693{
1694    BitmapWidget BW = (BitmapWidget) w;
1695
1696    if (BW->bitmap.grid != _switch)
1697	BWSwitchGrid(w);
1698}
1699
1700Boolean
1701BWQueryDashed(Widget w)
1702{
1703    BitmapWidget BW = (BitmapWidget) w;
1704
1705    return (BW->bitmap.dashed);
1706}
1707
1708void
1709BWSwitchDashed(Widget w)
1710{
1711    BitmapWidget BW = (BitmapWidget) w;
1712    XRectangle rectangle;
1713
1714    BWRedrawGrid(w, 0, 0, BW->bitmap.width - 1, BW->bitmap.height - 1);
1715
1716    rectangle.x = 0;
1717    rectangle.y = 0;
1718    rectangle.width = BW->core.width;
1719    rectangle.height = BW->core.height;
1720
1721    XSetClipRectangles(XtDisplay(BW),
1722		       BW->bitmap.frame_gc,
1723		       0, 0,
1724		       &rectangle, 1,
1725		       Unsorted);
1726
1727    XDrawRectangle(XtDisplay(BW), XtWindow(BW),
1728		   BW->bitmap.frame_gc,
1729		   InWindowX(BW, 0) - 1, InWindowY(BW, 0) - 1,
1730		   InWindowX(BW, BW->bitmap.width) - InWindowX(BW, 0) + 1,
1731		   InWindowY(BW, BW->bitmap.height) - InWindowY(BW, 0) + 1);
1732
1733    BW->bitmap.dashed ^= True;
1734    XSetFillStyle(XtDisplay(BW), BW->bitmap.frame_gc,
1735		  (BW->bitmap.dashed ? FillStippled : FillSolid));
1736
1737    XDrawRectangle(XtDisplay(BW), XtWindow(BW),
1738		   BW->bitmap.frame_gc,
1739		   InWindowX(BW, 0) - 1, InWindowY(BW, 0) - 1,
1740		   InWindowX(BW, BW->bitmap.width) - InWindowX(BW, 0) + 1,
1741		   InWindowY(BW, BW->bitmap.height) - InWindowY(BW, 0) + 1);
1742
1743    BWUnclip(w);
1744
1745    BWRedrawGrid(w, 0, 0, BW->bitmap.width - 1, BW->bitmap.height - 1);
1746}
1747
1748void
1749BWDashed(Widget w, Boolean _switch)
1750{
1751    BitmapWidget BW = (BitmapWidget) w;
1752
1753    if (BW->bitmap.dashed != _switch)
1754	BWSwitchDashed(w);
1755}
1756
1757static Boolean
1758SetValues(Widget old, Widget request, Widget new,
1759	  ArgList args, Cardinal *num_args) /* ARGSUSED */
1760{
1761  BitmapWidget oldbw = (BitmapWidget) old;
1762  BitmapWidget newbw = (BitmapWidget) new;
1763  Boolean resize = False;
1764  Boolean redisplay = False;
1765
1766#define NE(field) (oldbw->field != newbw->field)
1767
1768  if (NE(bitmap.grid))
1769    BWSwitchGrid(old);
1770
1771  if (NE(bitmap.dashed))
1772    BWSwitchDashed(old);
1773
1774  if (NE(bitmap.axes))
1775    BWSwitchAxes(old);
1776
1777  if (NE(bitmap.stippled))
1778    BWSwitchStippled(old);
1779
1780  if (NE(bitmap.proportional))
1781    resize = True;
1782
1783  if (NE(bitmap.filename) || NE(bitmap.basename)  || NE(bitmap.size))
1784    BWChangeNotify(old);
1785
1786  if (NE(bitmap.filename)) {
1787    if (newbw->bitmap.filename) {
1788      XtFree(oldbw->bitmap.filename);
1789      newbw->bitmap.filename = XtNewString(newbw->bitmap.filename);
1790    }
1791    else
1792      newbw->bitmap.filename = oldbw->bitmap.filename;
1793  }
1794
1795  if (NE(bitmap.basename)) {
1796    if (newbw->bitmap.basename) {
1797      XtFree(oldbw->bitmap.basename);
1798      newbw->bitmap.basename = XtNewString(newbw->bitmap.basename);
1799    }
1800    else
1801      newbw->bitmap.basename = oldbw->bitmap.basename;
1802  }
1803
1804  if (NE(bitmap.size)) {
1805    Dimension width, height;
1806
1807    if (BWParseSize(newbw->bitmap.size, &width, &height)) {
1808      ResizeGrid(newbw, width, height);
1809      resize = True;
1810    }
1811  }
1812
1813  if (NE(bitmap.margin) ||
1814      NE(bitmap.grid_tolerance) ||
1815      NE(bitmap.squareW) ||
1816      NE(bitmap.squareH) ||
1817      NE(core.height) ||
1818      NE(core.width))
1819    resize = True;
1820
1821  if (NE(bitmap.hot.x) || NE(bitmap.hot.y))
1822    BWSetHotSpot(old, newbw->bitmap.hot.x, newbw->bitmap.hot.y);
1823
1824  if (NE(bitmap.foreground_pixel) || NE(core.background_pixel)) {
1825    XSetForeground(XtDisplay(new),
1826		   newbw->bitmap.drawing_gc,
1827		   newbw->bitmap.foreground_pixel
1828		   ^
1829		   newbw->core.background_pixel);
1830    redisplay = True;
1831  }
1832
1833  if (NE(bitmap.frame_pixel) || NE(core.background_pixel)) {
1834    XSetForeground(XtDisplay(new),
1835		   newbw->bitmap.frame_gc,
1836		   newbw->bitmap.frame_pixel
1837		   ^
1838		   newbw->core.background_pixel);
1839    redisplay = True;
1840  }
1841
1842  if (NE(bitmap.dashes)) {
1843    XSetStipple(XtDisplay(new),
1844		newbw->bitmap.frame_gc,
1845		newbw->bitmap.dashes);
1846    redisplay = True;
1847  }
1848
1849  if (NE(bitmap.highlight_pixel) || NE(core.background_pixel)) {
1850    RedrawStippled(newbw);
1851    XSetForeground(XtDisplay(new),
1852		   newbw->bitmap.highlighting_gc,
1853		   newbw->bitmap.highlight_pixel
1854		   ^
1855		   newbw->core.background_pixel);
1856    RedrawStippled(newbw);
1857  }
1858
1859  if (NE(bitmap.stipple)) {
1860    RedrawStippled(newbw);
1861    XSetStipple(XtDisplay(new),
1862		newbw->bitmap.highlighting_gc,
1863		newbw->bitmap.stipple);
1864    RedrawStippled(newbw);
1865  }
1866
1867  if (resize) Resize((Widget)newbw);
1868
1869    return (redisplay || resize);
1870
1871#undef NE
1872}
1873
1874Boolean
1875BWQueryProportional(Widget w)
1876{
1877    BitmapWidget BW = (BitmapWidget) w;
1878
1879    return (BW->bitmap.proportional);
1880}
1881
1882void
1883BWSwitchProportional(Widget w)
1884{
1885    BitmapWidget BW = (BitmapWidget) w;
1886
1887    BW->bitmap.proportional ^= True;
1888
1889    Resize((Widget)BW);
1890    if (BW->core.visible)
1891	XClearArea(XtDisplay(BW), XtWindow(BW),
1892		   0, 0,
1893		   BW->core.width, BW->core.height,
1894		   True);
1895}
1896
1897#if 0
1898void
1899BWProportional(Widget w, Boolean _switch)
1900{
1901    BitmapWidget BW = (BitmapWidget) w;
1902
1903    if (BW->bitmap.proportional != _switch)
1904	BWSwitchProportional(w);
1905}
1906#endif
1907
1908void
1909BWTPaste(Widget w, XEvent *event, String *params, Cardinal *num_params)
1910{
1911    BitmapWidget BW = (BitmapWidget) w;
1912
1913    BWRequestSelection(w, event->xbutton.time, TRUE);
1914
1915    if (!BWQueryStored(w))
1916	return;
1917
1918    BWEngageRequest(w, RestoreRequest, False,
1919		    (char *)&(event->xbutton.state), sizeof(int));
1920
1921    OnePointHandler(w,
1922	       (BWStatus*) BW->bitmap.request_stack[BW->bitmap.current].status,
1923	       event, NULL);
1924}
1925
1926void
1927BWTMark(Widget w, XEvent *event, String *params, Cardinal *num_params)
1928{
1929    BitmapWidget BW = (BitmapWidget) w;
1930
1931    BWEngageRequest(w, MarkRequest, False,
1932		    (char *)&(event->xbutton.state), sizeof(int));
1933    TwoPointsHandler(w,
1934            (BWStatus*) BW->bitmap.request_stack[BW->bitmap.current].status,
1935	     event, NULL);
1936
1937}
1938
1939void
1940BWTMarkAll(Widget w, XEvent *event, String *params, Cardinal *num_params)
1941{
1942    BWMarkAll(w);
1943
1944    BWGrabSelection(w, event->xkey.time);
1945}
1946
1947void
1948BWTUnmark(Widget w, XEvent *event, String *params, Cardinal *num_params)
1949{
1950    BWUnmark(w);
1951}
1952
1953/*****************************************************************************/
1954