Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dticon / utils.c
1 /* $TOG: utils.c /main/9 1998/09/24 12:32:05 samborn $ */
2 /*********************************************************************
3 *  (c) Copyright 1993, 1994 Hewlett-Packard Company
4 *  (c) Copyright 1993, 1994 International Business Machines Corp.
5 *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
6 *  (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of
7 *      Novell, Inc.
8 **********************************************************************/
9 /******************************************************************************
10  **  Program:           dticon
11  **
12  **  Description:       X11-based multi-color icon editor
13  **
14  **  File:              utils.c, which contains the following subroutines or
15  **                     functions:
16  **                       Create_Gfx_Labels()
17  **                       Init_Editor()
18  **                       New_MagFactor()
19  **                       New_FileFormat()
20  **                       Icon_Coords()
21  **                       Tablet_Coords()
22  **                       Quantize()
23  **                       Repaint_Exposed_Tablet()
24  **                       Repaint_Tablet()
25  **                       Paint_Tile()
26  **                       Transfer_Back_Image()
27  **                       Init_Widget_List()
28  **                       Init_Pen_Colors()
29  **                       Init_Color_Table()
30  **                       Size_IconForm()
31  **                       Init_Icons()
32  **                       Abort()
33  **                       stat_out()
34  **                       Switch_FillSolids()
35  **                       Select_New_Pen()
36  **                       Backup_Icons()
37  **                       DoErrorDialog()
38  **                       DoQueryDialog()
39  **                       Do_GrabOp()
40  **                       LoadGrabbedImage()
41  **                       ParseAppArgs()
42  **                       ProcessAppArgs()
43  **                       Set_Gfx_Labels()
44  **                       PixelTableLookup()
45  **                       PixelTableClear()
46  **
47  ******************************************************************************
48  **
49  **  Copyright 1991 by Hewlett-Packard Company, 1990, 1991, 1992.
50  **  All rights are reserved.  Copying or reproduction of this program,
51  **  except for archival purposes, is prohibited without prior written
52  **  consent of Hewlett-Packard Company.
53  **
54  **  Hewlett-Packard makes no representations about the suitibility of this
55  **  software for any purpose.  It is provided "as is" without express or
56  **  implied warranty.
57  **
58  ******************************************************************************/
59 #include <stdio.h>
60 #include <sys/stat.h>
61 #include <X11/cursorfont.h>
62 #include <Xm/Protocols.h>
63 #include <Xm/Xm.h>
64 #include <Xm/XmP.h>
65 #include <Xm/MessageB.h>
66 #include <Xm/VendorSEP.h>
67 #include <Dt/UserMsg.h>
68 #include <Xm/DragC.h>
69 #include <Dt/Dnd.h>
70 #include "externals.h"
71 #include "main.h"
72 /* Copied from Xm/BaseClassI.h */
73 extern XmWidgetExtData _XmGetWidgetExtData( 
74                         Widget widget,
75 #if NeedWidePrototypes
76                         unsigned int extType) ;
77 #else
78                         unsigned char extType) ;
79 #endif /* NeedWidePrototypes */
80
81 #include "pixmaps/Circle.pm"
82 #include "pixmaps/CircleSolid.pm"
83 #include "pixmaps/Connected.pm"
84 #include "pixmaps/ConnectedClosed.pm"
85 #include "pixmaps/ConnecClosedSolid.pm"
86 #include "pixmaps/Ellipse.pm"
87 #include "pixmaps/EllipseSolid.pm"
88 #include "pixmaps/Eraser.pm"
89 #include "pixmaps/Rectangle.pm"
90 #include "pixmaps/RectangleSolid.pm"
91 #include "pixmaps/PaintBucket.pm"
92 #include "pixmaps/Pencil.pm"
93 #include "pixmaps/Line.pm"
94 #include "pixmaps/SelectArea.pm"
95
96 #include "bitmaps/q_mark.xbm"
97
98 extern Widget  color_pb1, color_pb2, color_pb3, color_pb4,
99                color_pb5, color_pb6, color_pb7, color_pb8;
100 extern Widget  grey_pb1, grey_pb2, grey_pb3, grey_pb4,
101                grey_pb5, grey_pb6, grey_pb7, grey_pb8;
102 extern Widget  fgColorToggle, bgColorToggle, tsColorToggle,
103                bsColorToggle, selectColorToggle,
104                transparentColorToggle;
105 extern Widget  pointButton, floodButton, lineButton, polylineButton,
106                rectangleButton, polygonButton, circleButton,
107                ellipseButton, eraseButton, selectButton;
108 extern Widget  viewport, tablet, tabletBorder, tabletFrame;
109 extern Widget  iconForm, iconSize, monoLabel;
110 extern Widget  fillToggle, magMenu_8x_tb;
111 extern Widget  formatMenu_xbm_tb, formatMenu_xpm_tb;
112 extern Widget  optionsMenu_grid, menu1, queryDialog, stdErrDialog;
113 extern Widget  tablet_wid;
114 extern Window  tablet_win;
115
116 static int jskXerrorDebug();
117 static int jskXerrorIODebug();
118
119 Widget editMenu_undo_pb;
120
121 void GetSessionInfo( void );
122 void Set_Gfx_Labels( Boolean );
123 void Init_Icons(
124                 Dimension width,
125                 Dimension height,
126                 Boolean saveFlag);
127 int PixelTableLookup(
128                 Pixel pixelIn,
129                 Boolean allocNew);
130 extern void *Process_DropCheckOp(
131                 Widget,
132                 XtPointer,
133                 XtPointer);
134 extern void *Process_DropOp(
135                 Widget,
136                 XtPointer,
137                 XtPointer);
138 extern void Repaint_Tablet(Window, int, int, int, int);
139 extern void Init_Widget_List(void);
140 extern void Init_Pen_Colors(Widget);
141 extern void Init_Color_Table(void);
142 extern void RegisterDropSites(void);
143 extern void Abort(char *);
144 extern void DoErrorDialog(char *);
145
146 char dash_list[2] = {1,1};
147 char err_str[80];
148 char start_file[256];
149 char start_size[80];
150 Widget clip_wid;
151 GC scratch_gc;
152 Position x_margin, y_margin;
153 Pixmap pointPix, floodPix, linePix, polylinePix, rectPix;
154 Pixmap polygonPix, circlePix, ellipsePix, eraserPix, selectPix;
155 Pixmap rectSolidPix, circleSolidPix, polygonSolidPix, ellipseSolidPix;
156 extern int successFormat, x_hot, y_hot;
157 extern unsigned int width_ret, height_ret;
158
159 /*  Structure used on a save session to see if a dt is iconic  */
160 typedef struct
161 {
162    int state;
163    Window icon;
164 } WM_STATE;
165
166 /***************************************************************************
167  *                                                                         *
168  * Routine:   Create_Gfx_Labels                                            *
169  *                                                                         *
170  * Purpose:   Initialize all the global variables used by the icon editor. *
171  *                                                                         *
172  ***************************************************************************/
173
174 void
175 Create_Gfx_Labels(
176         unsigned long fg,
177         unsigned long bg )
178 {
179   Arg args[10];
180   int i, depth;
181   Pixmap q_markPix, mask;
182
183   depth = XDefaultDepth(dpy, screen);
184
185 /**********
186   pointPix = XCreatePixmapFromBitmapData(dpy, root,
187                         point_bits, point_width, point_height,
188                         fg, bg, depth);
189   floodPix = XCreatePixmapFromBitmapData(dpy, root,
190                         flood_bits, flood_width, flood_height,
191                         fg, bg, depth);
192   linePix = XCreatePixmapFromBitmapData(dpy, root,
193                         line_bits, line_width, line_height,
194                         fg, bg, depth);
195   polylinePix = XCreatePixmapFromBitmapData(dpy, root,
196                         polyline_bits, polyline_width, polyline_height,
197                         fg, bg, depth);
198   rectPix = XCreatePixmapFromBitmapData(dpy, root,
199                         rectangle_bits, rectangle_width, rectangle_height,
200                         fg, bg, depth);
201   polygonPix = XCreatePixmapFromBitmapData(dpy, root,
202                         polygon_bits, polygon_width, polygon_height,
203                         fg, bg, depth);
204   circlePix = XCreatePixmapFromBitmapData(dpy, root,
205                         circle_bits, circle_width, circle_height,
206                         fg, bg, depth);
207   ellipsePix = XCreatePixmapFromBitmapData(dpy, root,
208                         ellipse_bits, ellipse_width, ellipse_height,
209                         fg, bg, depth);
210   eraserPix = XCreatePixmapFromBitmapData(dpy, root,
211                         eraser_bits, eraser_width, eraser_height,
212                         fg, bg, depth);
213   selectPix = XCreatePixmapFromBitmapData(dpy, root,
214                         select_bits, select_width, select_height,
215                         fg, bg, depth);
216 **********/
217
218   xpm_ReadAttribs.valuemask = READ_FLAGS;
219   xpm_ReadAttribs.colorsymbols = colorSymbols;
220   xpm_ReadAttribs.numsymbols = NUM_PENS;
221
222   status = _DtXpmCreatePixmapFromData(dpy, root, Circle, &circlePix, &mask,
223                                 &xpm_ReadAttribs);
224   if (status != XpmSuccess) Abort(GETSTR(10,2, "Cannot initialize button icon for circle"));
225   status = _DtXpmCreatePixmapFromData(dpy, root, CircleSolid, &circleSolidPix,
226                                 &mask, &xpm_ReadAttribs);
227   if (status != XpmSuccess) Abort(GETSTR(10,4, "Cannot initialize button icon for solid circle"));
228   status = _DtXpmCreatePixmapFromData(dpy, root, Connected, &polylinePix, &mask,
229                                 &xpm_ReadAttribs);
230   if (status != XpmSuccess) Abort(GETSTR(10,6, "Cannot initialize button icon for polyline"));
231   status = _DtXpmCreatePixmapFromData(dpy, root, ConnectedClosed, &polygonPix,
232                                 &mask, &xpm_ReadAttribs);
233   if (status != XpmSuccess) Abort(GETSTR(10,8, "Cannot initialize button icon for polygon"));
234   status = _DtXpmCreatePixmapFromData(dpy, root, ConnecClosedSolid,
235                         &polygonSolidPix, &mask, &xpm_ReadAttribs);
236   if (status != XpmSuccess) Abort(GETSTR(10,10, "Cannot initialize button icon for solid polygon"));
237   status = _DtXpmCreatePixmapFromData(dpy, root, Ellipse, &ellipsePix, &mask,
238                                 &xpm_ReadAttribs);
239   if (status != XpmSuccess) Abort(GETSTR(10,12, "Cannot initialize button icon for ellipse"));
240   status = _DtXpmCreatePixmapFromData(dpy, root, EllipseSolid, &ellipseSolidPix,
241                                 &mask, &xpm_ReadAttribs);
242   if (status != XpmSuccess) Abort(GETSTR(10,14, "Cannot initialize button icon for solid ellipse"));
243   status = _DtXpmCreatePixmapFromData(dpy, root, Eraser, &eraserPix, &mask,
244                                 &xpm_ReadAttribs);
245   if (status != XpmSuccess) Abort(GETSTR(10,16, "Cannot initialize button icon for eraser"));
246   status = _DtXpmCreatePixmapFromData(dpy, root, Line, &linePix, &mask,
247                                 &xpm_ReadAttribs);
248   if (status != XpmSuccess) Abort(GETSTR(10,18, "Cannot initialize button icon for line"));
249   status = _DtXpmCreatePixmapFromData(dpy, root, PaintBucket, &floodPix, &mask,
250                                 &xpm_ReadAttribs);
251   if (status != XpmSuccess) Abort(GETSTR(10,20, "Cannot initialize button icon for flood"));
252   status = _DtXpmCreatePixmapFromData(dpy, root, Pencil, &pointPix, &mask,
253                                 &xpm_ReadAttribs);
254   if (status != XpmSuccess) Abort(GETSTR(10,22, "Cannot initialize button icon for point"));
255   status = _DtXpmCreatePixmapFromData(dpy, root, Rectangle, &rectPix, &mask,
256                                 &xpm_ReadAttribs);
257   if (status != XpmSuccess) Abort(GETSTR(10,24, "Cannot initialize button icon for rectangle"));
258   status = _DtXpmCreatePixmapFromData(dpy, root, RectangleSolid, &rectSolidPix,
259                                 &mask, &xpm_ReadAttribs);
260   if (status != XpmSuccess) Abort(GETSTR(10,26, "Cannot initialize button icon for solid rectangle"));
261   status = _DtXpmCreatePixmapFromData(dpy, root, SelectArea, &selectPix, &mask,
262                                 &xpm_ReadAttribs);
263   if (status != XpmSuccess) Abort(GETSTR(10,28, "Cannot initialize button icon for select"));
264
265   q_markPix = XCreatePixmapFromBitmapData(dpy, root,
266                         (char*)q_mark_bits, q_mark_width, q_mark_height,
267                         fg, bg, depth);
268
269   i = 0;
270   XtSetArg(args[i], XmNlabelPixmap, pointPix); i++;
271   XtSetValues(pointButton, args, i);
272   i = 0;
273   XtSetArg(args[i], XmNlabelPixmap, linePix); i++;
274   XtSetValues(lineButton, args, i);
275   i = 0;
276   XtSetArg(args[i], XmNlabelPixmap, eraserPix); i++;
277   XtSetValues(eraseButton, args, i);
278   i = 0;
279   XtSetArg(args[i], XmNlabelPixmap, floodPix); i++;
280   XtSetValues(floodButton, args, i);
281   i = 0;
282   XtSetArg(args[i], XmNlabelPixmap, polylinePix); i++;
283   XtSetValues(polylineButton, args, i);
284   i = 0;
285   XtSetArg(args[i], XmNlabelPixmap, selectPix); i++;
286   XtSetValues(selectButton, args, i);
287   i = 0;
288   XtSetArg(args[i], XmNlabelPixmap, q_markPix); i++;
289   XtSetValues(queryDialog, args, i);
290
291   Set_Gfx_Labels(HOLLOW);
292 }
293
294 /***************************************************************************
295  *                                                                         *
296  * Routine:   Init_Editor                                                  *
297  *                                                                         *
298  * Purpose:   Initialize all the global variables, states, widgets, etc,   *
299  *            for the icon editor.  This is a long, messy, somewhat        *
300  *            rambling routine.                                            *
301  *                                                                         *
302  ***************************************************************************/
303
304 void
305 Init_Editor(
306         Widget wid )
307 {
308   Window win;
309   Arg args[10];
310   int i;
311   Position lx, ly;
312
313 /*** window ID of tablet ***/
314   tablet_win = NULL;
315
316 /*** Nothing needs to be saved, yet ***/
317   Dirty = False;
318
319 /*** Initial Graphics states, pen color, etc. ***/
320   GraphicsOp = POINT;
321   CurrentColor = COLOR1;
322   ColorBlock = STATIC_COLOR;
323   FillSolids = False;
324   MagFactor = 8;
325   pointCount = 0;
326
327 /*** file I/O related globals ***/
328   last_fname[0] = NULL;
329   X_Hot = -1;
330   Y_Hot = -1;
331
332   XSetErrorHandler(jskXerrorDebug);
333   XSetIOErrorHandler(jskXerrorIODebug);
334
335 /*** Xlib-related globals ***/
336   dpy = XtDisplay(wid);
337   win = XtWindow(wid);
338   root = DefaultRootWindow(dpy);
339   screen = DefaultScreen(dpy);
340   screen_ptr = XtScreen(wid);
341   black_pixel = BlackPixel(dpy, screen);
342   white_pixel = WhitePixel(dpy, screen);
343   Cmap = DefaultColormap(dpy, screen);
344
345 /*** initialize global pixel table data ***/
346   pixelTable.pixelTableSize = 0;
347   pixelTable.numItems = 0;
348   pixelTable.lastFound = 0;
349   pixelTable.item = NULL;
350
351 /*** Initialize the GCs used by the app. ***/
352   Color_gc = XCreateGC(dpy, root, 0, 0);
353   Mono_gc = XCreateGC(dpy, root, 0, 0);
354   Grid_gc = XCreateGC(dpy, root, 0, 0);
355   Erase_gc = XCreateGC(dpy, root, 0, 0);
356   Flicker_gc = XCreateGC(dpy, root, 0, 0);
357   scratch_gc = XCreateGC(dpy, root, 0, 0);
358   XSetState(dpy, Flicker_gc, black_pixel, white_pixel, GXinvert, 0x1);
359   XSetSubwindowMode(dpy, Flicker_gc, IncludeInferiors);
360   XSetDashes(dpy, Grid_gc, 0, dash_list, 2);
361   XSetLineAttributes(dpy, Grid_gc, 0, LineDoubleDash, CapButt, JoinMiter);
362
363 /*** Initialize the widget variables ***/
364   Init_Widget_List();
365
366 /*** Initialize the pen colors and the internal color table ***/
367   Init_Pen_Colors(wid);
368   Init_Color_Table();
369   XSetForeground(dpy, Erase_gc, Transparent);
370
371 /*** configure the color and mono icons to their initial size ***/
372   Init_Icons(icon_width, icon_height, DO_NOT_SAVE);
373
374   xrdb.useBMS = FALSE;
375   DtInitialize (dpy, wid, progName, progName);
376
377 /*** Drop site registration must occur after DtInitialize() ***/
378
379   RegisterDropSites();
380
381   multiClickTime = XtGetMultiClickTime(dpy);
382
383 /*** Now, do all the tedious widget initialization ***/
384   i = 0;
385   XtSetArg(args[i], XmNset, True); i++;
386   XtSetValues(StaticWid[CurrentColor], args, i);
387   XtSetValues(GraphicOpsWid[GraphicsOp], args, i);
388   XtSetValues(magMenu_8x_tb, args, i);
389   XtSetValues(optionsMenu_grid, args, i);
390   XtSetValues(formatMenu_xpm_tb, args, i);
391   i = 0;
392   XtSetArg(args[i], XmNbackground, Transparent); i++;
393   XtSetValues(tablet_wid, args, i);
394   XtSetValues(tabletBorder, args, i);
395   XSetForeground(dpy, Color_gc, StaticPen[0]);
396   XSetForeground(dpy, Mono_gc, StaticMono[0]);
397   i = 0;
398   XtSetArg(args[i], XmNset, FillSolids); i++;
399   XtSetValues(fillToggle, args, i);
400   i = 0;
401   XtSetArg(args[i], XmNclipWindow, &clip_wid); i++;
402   XtGetValues(viewport, args, i);
403
404   x_margin = 0;
405   y_margin = 0;
406
407 #ifdef DEBUG
408   if (debug) {
409     stat_out("DEFAULT TIME-OUT VALUE IS %d MILLISECONDS\n", multiClickTime);
410     stat_out("****CLIP WINDOW WIDGET = %d\n", clip_wid);
411     stat_out("    TABLET OFFSETS [x,y] = [%d,%d]\n", x_margin, y_margin);
412    }
413 #endif
414
415   i = 0;
416   XtSetArg(args[i], XmNbackground, Transparent); i++;
417   XtSetValues(clip_wid, args, i);
418   i = 0;
419   XtSetArg(args[i], XmNset, False); i++;
420   XtSetValues(floodButton, args, i);
421   XtSetValues(lineButton, args, i);
422   XtSetValues(polylineButton, args, i);
423   XtSetValues(rectangleButton, args, i);
424   XtSetValues(polygonButton, args, i);
425   XtSetValues(circleButton, args, i);
426   XtSetValues(ellipseButton, args, i);
427   XtSetValues(eraseButton, args, i);
428   XtSetValues(selectButton, args, i);
429   i = 0;
430   XtSetArg(args[i], XmNset, True); i++;
431   XtSetValues(pointButton, args, i);
432 }
433
434
435 /***************************************************************************
436  *                                                                         *
437  * Routine:   GetMarginData                                                *
438  *                                                                         *
439  * Purpose:   We need to get margin data AFTER these widgets are realized  *
440  *            in order to get valid data... so do it here                  *
441  *                                                                         *
442  ***************************************************************************/
443
444 void
445 GetMarginData( void )
446 {
447   Arg args[10];
448   int i;
449   Position lx, ly;
450
451
452 #ifdef DEBUG
453   if (debug)
454     stat_out("****** Getting margin data: x=%d y=%d\n", x_margin, y_margin);
455 #endif
456
457   i = 0;
458   XtSetArg(args[i], XmNx, &lx); i++;
459   XtSetArg(args[i], XmNy, &ly); i++;
460   XtGetValues(tabletFrame, args, i);
461   x_margin = lx;
462   y_margin = ly;
463   i = 0;
464   XtSetArg(args[i], XmNx, &lx); i++;
465   XtSetArg(args[i], XmNy, &ly); i++;
466   XtGetValues(tablet_wid, args, i);
467   x_margin += lx;
468   y_margin += ly;
469
470 #ifdef DEBUG
471   if (debug)
472     stat_out("******         margin data: x=%d y=%d\n", x_margin, y_margin);
473 #endif
474
475 }
476
477
478 /***************************************************************************
479  *                                                                         *
480  * Routine:   New_MagFactor                                                *
481  *                                                                         *
482  * Purpose:   The user has just selected a new magnification factor for    *
483  *            the fat pixels on the tablet.  Update the MagFactor global   *
484  *            variable and reapaint the visible portion of the tablet to   *
485  *            reflect the change.                                          *
486  *                                                                         *
487  ***************************************************************************/
488
489 void
490 New_MagFactor(
491         int new_value )
492 {
493   Arg args[10];
494   int i;
495
496 #ifdef DEBUG
497   if (debug)
498     stat_out("****** Changing MagFactor to %d\n", new_value);
499 #endif
500
501   MagFactor = new_value;
502   i = 0;
503   XtSetArg(args[i], XmNwidth, (icon_width*MagFactor)); i++;
504   XtSetArg(args[i], XmNheight, (icon_height*MagFactor)); i++;
505   XtSetValues(tablet_wid, args, i);
506   if (Selected)
507     Set_HotBox_Coords();
508 /* This code does not seem to be needed and since it slows down
509    the grid drawing I'll take it out */
510   /*Repaint_Exposed_Tablet();*/
511 }
512
513
514 /***************************************************************************
515  *                                                                         *
516  * Routine:   New_FileFormat                                               *
517  *                                                                         *
518  * Purpose:   Update the fileFormat value to reflect the user's current    *
519  *            choice of default file output formats.                       *
520  *                                                                         *
521  ***************************************************************************/
522
523 void
524 New_FileFormat(
525         int new_value )
526 {
527
528 #ifdef DEBUG
529   if (debug) {
530     stat_out("****** Changing Output File Format to ");
531     switch (new_value) {
532       case FORMAT_XPM : stat_out("XPM\n");
533                         break;
534       case FORMAT_XBM : stat_out("XBM\n");
535                         break;
536       default         : stat_out("UNKNOWN\n");
537                         break;
538      } /* switch */
539    } /* if */
540 #endif
541
542   fileFormat = new_value;
543
544 }
545
546
547 /***************************************************************************
548  *                                                                         *
549  * Routine:   Icon_Coords                                                  *
550  *                                                                         *
551  * Purpose:   Convert a set of [x,y] values (acquired from the tablet)     *
552  *            into the equivalent [x,y] values they represent on the       *
553  *            actual icon being created/modified.                          *
554  *                                                                         *
555  ***************************************************************************/
556
557 void
558 Icon_Coords(
559         int normal_x,
560         int normal_y,
561         int *fat_x,
562         int *fat_y )
563 {
564   *fat_x = normal_x / MagFactor;
565   *fat_y = normal_y / MagFactor;
566 }
567
568
569 /***************************************************************************
570  *                                                                         *
571  * Routine:   Tablet_Coords                                                *
572  *                                                                         *
573  * Purpose:   Convert a set of fat [x,y] values back into raw [x,y] values *
574  *            which map to the top-left corner of the fat pixel value.     *
575  *                                                                         *
576  ***************************************************************************/
577
578 void
579 Tablet_Coords(
580         int fat_x,
581         int fat_y,
582         int *raw_x,
583         int *raw_y )
584 {
585   *raw_x = fat_x * MagFactor;
586   *raw_y = fat_y * MagFactor;
587 }
588
589
590 /***************************************************************************
591  *                                                                         *
592  * Routine:   Quantize                                                     *
593  *                                                                         *
594  * Purpose:   Adjust a set of [x,] values so that they mark the top-left   *
595  *            corner (or the middle, depending on the 'center' flag) of    *
596  *            whatever 'fat' pixel they map onto.  This will insure that   *
597  *            any operation involving rubberband lines leaps from fat      *
598  *            pixel center to fat pixel center, providing a clear visual   *
599  *            indicator of which pixel currently contains the line/point.  *
600  *                                                                         *
601  ***************************************************************************/
602
603 void
604 Quantize(
605         int *x,
606         int *y,
607         int center )
608 {
609   int lx, ly, half;
610
611   lx = *x;
612   ly = *y;
613   half = MagFactor/2;
614   if ((lx%MagFactor) != 0)
615     lx = (lx / MagFactor) * MagFactor;
616   if ((ly%MagFactor) != 0)
617     ly = (ly / MagFactor) * MagFactor;
618   if (center) {
619     lx += half;
620     ly += half;
621    }
622   *x = lx;
623   *y = ly;
624 }
625
626
627 /***************************************************************************
628  *                                                                         *
629  * Routine:   Repaint_Exposed_Tablet                                       *
630  *                                                                         *
631  * Purpose:   Repaint the rectangular section of the tablet currently      *
632  *            visible in the clipping area widget of the scrolled window   *
633  *            widget.  To do this, we get the current width and height     *
634  *            of the clipping area widget, the current width and height    *
635  *            of the drawing area manager widget (the clipping area        *
636  *            widget's immediate child), and the x and y position of the   *
637  *            drawing area manager widget.  This will allow us to cal-     *
638  *            culate what portion of the tablet (drawn button widget) is   *
639  *            currently visible in the clipping area widget.  We then      *
640  *            request th Repaint_Tablet() routine to repaint that portion  *
641  *            of the drawn button.                                         *
642  *                                                                         *
643  ***************************************************************************/
644
645 void
646 Repaint_Exposed_Tablet( void )
647 {
648   int i;
649   Arg args[10];
650   Position t_x, t_y;
651   Dimension c_width, c_height, t_width, t_height;
652
653   i = 0;
654   XtSetArg(args[i], XmNwidth, &c_width); i++;
655   XtSetArg(args[i], XmNheight, &c_height); i++;
656   XtGetValues(clip_wid, args, i);
657   i = 0;
658   XtSetArg(args[i], XmNx, &t_x); i++;
659   XtSetArg(args[i], XmNy, &t_y); i++;
660   XtSetArg(args[i], XmNwidth, &t_width); i++;
661   XtSetArg(args[i], XmNheight, &t_height); i++;
662   XtGetValues(tabletBorder, args, i);
663
664   t_x += x_margin;
665   t_y += y_margin;
666   t_x = -t_x;
667   t_y = -t_y;
668   if (t_x < 0) t_x = 0;
669   if (t_y < 0) t_y = 0;
670
671   Repaint_Tablet(tablet_win, t_x, t_y, c_width, c_height);
672 }
673
674
675 /***************************************************************************
676  *                                                                         *
677  * Routine:   Repaint_Tablet                                               *
678  *                                                                         *
679  * Purpose:   Repaint the rectangular section of the tablet described by   *
680  *            the [x,y,width,height] values in the XRectangle.             *
681  *                                                                         *
682  ***************************************************************************/
683
684 void
685 Repaint_Tablet(
686         Window win,
687         int x,
688         int y,
689         int width,
690         int height )
691 {
692   int i, j, lx, ly;
693   XImage *scratch_img;
694
695   scratch_img = XGetImage(dpy, color_icon, 0, 0, icon_width, icon_height,
696                 AllPlanes, ZPixmap);
697 #ifdef DEBUG
698   if (debug)
699     stat_out("****** Repaint_Tablet: x,y=%d,%d w,h=%d,%d\n", x,y,width,height);
700 #endif
701
702   for (i=x; i<x+width+MagFactor; i+=MagFactor)
703     for (j=y; j<y+height+MagFactor; j+=MagFactor) {
704       Icon_Coords(i, j, &lx, &ly);
705       if ((lx >= 0) && (lx < icon_width) &&
706           (ly >= 0) && (ly < icon_height)) {
707         XSetForeground(dpy, scratch_gc, XGetPixel(scratch_img, lx, ly));
708         XFillRectangle(dpy, tablet_win, scratch_gc,
709         lx*MagFactor, ly*MagFactor, MagFactor, MagFactor);
710         if (hotSpot)
711           if ((lx == X_Hot) && (ly == Y_Hot)) {
712             XDrawLine(dpy, tablet_win, Grid_gc,
713             lx*MagFactor, ly*MagFactor+MagFactor, lx*MagFactor+MagFactor, ly*MagFactor);
714             XDrawLine(dpy, tablet_win, Grid_gc,
715             lx*MagFactor, ly*MagFactor, lx*MagFactor+MagFactor, ly*MagFactor+MagFactor);
716           }
717        } /* if */
718      } /* for */
719
720   Quantize(&x, &y, False);
721   width += (MagFactor*2);
722   height += (MagFactor*2);
723
724 /*
725    Draw the grid if Enabled....
726 */
727   if (GridEnabled) {
728     for (i=x; i<=x+width+MagFactor; i+=MagFactor)
729       XDrawLine(dpy, win, Grid_gc, i, y, i, (y+height));
730     for (i=y; i<=y+height+MagFactor; i+=MagFactor)
731       XDrawLine(dpy, win, Grid_gc, x, i, (x+width), i);
732    }
733
734
735   XDestroyImage(scratch_img);
736 }
737
738
739 /***************************************************************************
740  *                                                                         *
741  * Routine:   Paint_Tile                                                   *
742  *                                                                         *
743  * Purpose:   Paint a single rectangular tile of size MagFactor x          *
744  *            MagFactor with the color supplied in the passed GC.          *
745  *            The X and Y parameters are coordinates for the 1:1           *
746  *            sized icon, and not direct coordinates for the tablet.       *
747  *                                                                         *
748  ***************************************************************************/
749
750 void
751 Paint_Tile(
752         int x,
753         int y,
754         GC gc )
755 {
756   XFillRectangle(dpy, tablet_win, gc,
757         x*MagFactor, y*MagFactor, MagFactor, MagFactor);
758
759   if (GridEnabled)
760     XDrawRectangle(dpy, tablet_win, Grid_gc,
761         x*MagFactor, y*MagFactor, MagFactor, MagFactor);
762
763   if (hotSpot)
764     if ((x == X_Hot) && (y == Y_Hot)) {
765       XDrawLine(dpy, tablet_win, Grid_gc,
766         x*MagFactor, y*MagFactor+MagFactor, x*MagFactor+MagFactor, y*MagFactor);
767       XDrawLine(dpy, tablet_win, Grid_gc,
768         x*MagFactor, y*MagFactor, x*MagFactor+MagFactor, y*MagFactor+MagFactor);
769      }
770 }
771
772
773 /***************************************************************************
774  *                                                                         *
775  * Routine:   Transfer_Back_Image                                          *
776  *                                                                         *
777  * Purpose:   Paint a single rectangular tile of size MagFactor x          *
778  *            MagFactor with the color supplied in the passed GC.          *
779  *            The [x,y] coordinate pairs are both icon coordinates,        *
780  *            not tablet coordinates.                                      *
781  *                                                                         *
782  ***************************************************************************/
783
784 void
785 Transfer_Back_Image(
786         int x1,
787         int y1,
788         int x2,
789         int y2,
790         Boolean tflag )
791 {
792   int min_x, min_y, max_x, max_y, i, j;
793   XImage *scratch_img;
794
795 #ifdef DEBUG
796   if (debug) {
797     stat_out("Entering Transfer_Back_Image\n");
798     stat_out("Values are x1:%d, y1:%d, x2:%d, y2:%d, flag = ",
799                 x1, y1, x2, y2);
800     stat_out("    icon size is width:%d, height:%d\n", icon_width, icon_height);
801     switch(tflag) {
802       case HOLLOW : stat_out("HOLLOW\n");
803                     break;
804       case FILL   : stat_out("FILL\n");
805                     break;
806       default     : stat_out("UNKNOWN\n");
807                     break;
808      } /* switch */
809    }
810 #endif
811
812   min_x = ((x1 < x2) ? x1 : x2);
813   min_y = ((y1 < y2) ? y1 : y2);
814   max_x = ((x1 > x2) ? x1 : x2);
815   max_y = ((y1 > y2) ? y1 : y2);
816
817 /*** make sure max_x and max_y are within icon ***/
818   if (max_x >= icon_width)
819     max_x = icon_width-1;
820   if (max_y >= icon_height)
821     max_y = icon_height-1;
822
823   scratch_img = XGetImage(dpy, color_icon, 0, 0, icon_width, icon_height,
824                 AllPlanes, ZPixmap);
825 /*** do the entire rectangular area... ***/
826   if (tflag == FILL) {
827     for (i = min_x; i <= max_x; i++)
828       for (j = min_y; j <= max_y; j++) {
829         XSetForeground(dpy, scratch_gc, XGetPixel(scratch_img, i, j));
830         Paint_Tile(i, j, scratch_gc);
831        } /* for */
832    } /* if */
833 /*** ...or just do the border of rectangle ***/
834   else {
835     for (i = min_x; i <= max_x; i++) {
836       XSetForeground(dpy, scratch_gc, XGetPixel(scratch_img, i, min_y));
837       Paint_Tile(i, min_y, scratch_gc);
838      }
839     for (i = min_x; i <= max_x; i++) {
840       XSetForeground(dpy, scratch_gc, XGetPixel(scratch_img, i, max_y));
841       Paint_Tile(i, max_y, scratch_gc);
842      }
843     for (i = min_y; i <= max_y; i++) {
844       XSetForeground(dpy, scratch_gc, XGetPixel(scratch_img, min_x, i));
845       Paint_Tile(min_x, i, scratch_gc);
846      }
847     for (i = min_y; i <= max_y; i++) {
848       XSetForeground(dpy, scratch_gc, XGetPixel(scratch_img, max_x, i));
849       Paint_Tile(max_x, i, scratch_gc);
850      }
851    } /* else */
852   XDestroyImage(scratch_img);
853
854 #ifdef DEBUG
855   if (debug)
856     stat_out("Leaving Transfer_Back_Image\n");
857 #endif
858
859 }
860
861
862 /***************************************************************************
863  *                                                                         *
864  * Routine:   Init_Widget_list                                             *
865  *                                                                         *
866  * Purpose:   Initialize all the pen color widgets into 2 widget ID        *
867  *            arrays, to simplify referencing them later.                  *
868  *                                                                         *
869  ***************************************************************************/
870
871 void
872 Init_Widget_List( void )
873 {
874
875
876   GraphicOpsWid[POINT]     = pointButton;
877   GraphicOpsWid[FLOOD]     = floodButton;
878   GraphicOpsWid[LINE]      = lineButton;
879   GraphicOpsWid[POLYLINE]  = polylineButton;
880   GraphicOpsWid[RECTANGLE] = rectangleButton;
881   GraphicOpsWid[POLYGON]   = polygonButton;
882   GraphicOpsWid[CIRCLE]    = circleButton;
883   GraphicOpsWid[ELLIPSE]   = ellipseButton;
884   GraphicOpsWid[ERASER]    = eraseButton;
885   GraphicOpsWid[SELECT]    = selectButton;
886
887   DynamicWid[BG_COLOR-BG_COLOR]     = bgColorToggle;
888   DynamicWid[FG_COLOR-BG_COLOR]     = fgColorToggle;
889   DynamicWid[TS_COLOR-BG_COLOR]     = tsColorToggle;
890   DynamicWid[BS_COLOR-BG_COLOR]     = bsColorToggle;
891   DynamicWid[SELECT_COLOR-BG_COLOR] = selectColorToggle;
892   DynamicWid[TRANS_COLOR-BG_COLOR]  = transparentColorToggle;
893
894   StaticWid[COLOR1] = color_pb1;
895   StaticWid[COLOR2] = color_pb2;
896   StaticWid[COLOR3] = color_pb3;
897   StaticWid[COLOR4] = color_pb4;
898   StaticWid[COLOR5] = color_pb5;
899   StaticWid[COLOR6] = color_pb6;
900   StaticWid[COLOR7] = color_pb7;
901   StaticWid[COLOR8] = color_pb8;
902   StaticWid[GREY1]  = grey_pb1;
903   StaticWid[GREY2]  = grey_pb2;
904   StaticWid[GREY3]  = grey_pb3;
905   StaticWid[GREY4]  = grey_pb4;
906   StaticWid[GREY5]  = grey_pb5;
907   StaticWid[GREY6]  = grey_pb6;
908   StaticWid[GREY7]  = grey_pb7;
909   StaticWid[GREY8]  = grey_pb8;
910
911   tablet_wid = tablet;
912 }
913
914
915 /***************************************************************************
916  *                                                                         *
917  * Routine:   Init_Pen_Colors                                              *
918  *                                                                         *
919  * Purpose:   Initialize all the pen colors (both Static and Dynamic) and  *
920  *            set the appropriate fg/bg colors for each pen button widget  *
921  *            to reflect this.                                             *
922  *                                                                         *
923  ***************************************************************************/
924
925 void
926 Init_Pen_Colors(
927         Widget wid )
928 {
929   Window win;
930   Pixel  transFg;
931   XColor exact_def;
932   Arg arg[10];
933   int i, j, pixelTableIndex;
934
935   i = 0;
936   XtSetArg(arg[i], XmNbackground, &Background); i++;
937   XtGetValues(wid, arg, i);
938   XmGetColors(screen_ptr, Cmap, Background, &Foreground, &TopShadow,
939                 &BottomShadow, &Select);
940
941 #ifdef DEBUG
942   if (debug)
943     stat_out("Return from XmGetColors()\n");
944 #endif
945
946 /*** Set FOREGROUND Button fg/bg colors ***/
947   i = 0;
948   XtSetArg(arg[i], XmNbackground, Foreground); i++;
949   pixelTableIndex = PixelTableLookup (Foreground, False);
950   if (PIXEL_TABLE_MONO(pixelTableIndex) == white_pixel) {
951     XtSetArg(arg[i], XmNforeground, black_pixel); i++;
952   }
953   else {
954     XtSetArg(arg[i], XmNforeground, white_pixel); i++;
955   }
956   XtSetValues(fgColorToggle, arg, i);
957
958 /*** Set BACKGROUND Button fg/bg colors ***/
959   i = 0;
960   XtSetArg(arg[i], XmNbackground, Background); i++;
961   XtSetArg(arg[i], XmNforeground, Foreground); i++;
962   XtSetValues(bgColorToggle, arg, i);
963
964 /*** Set TOP_SHADOW Button fg/bg colors ***/
965   i = 0;
966   XtSetArg(arg[i], XmNbackground, TopShadow); i++;
967   if (TopShadow == Foreground)  /* B & W */
968     { XtSetArg(arg[i], XmNforeground, Background); i++; }
969   else
970     { XtSetArg(arg[i], XmNforeground, Foreground); i++; }
971   XtSetValues(tsColorToggle, arg, i);
972
973 /*** Set BOTTOM_SHADOW Button fg/bg colors ***/
974   i = 0;
975   XtSetArg(arg[i], XmNbackground, BottomShadow); i++;
976   if (BottomShadow == Foreground) /* B & W */
977     { XtSetArg(arg[i], XmNforeground, Background); i++; }
978   else
979     { XtSetArg(arg[i], XmNforeground, Foreground); i++; }
980   XtSetValues(bsColorToggle, arg, i);
981
982 /*** Set SELECT Button fg/bg colors ***/
983   i = 0;
984   XtSetArg(arg[i], XmNbackground, Select); i++;
985   XtSetArg(arg[i], XmNforeground, Foreground); i++;
986   XtSetValues(selectColorToggle, arg, i);
987
988 /*** Set TRANSPARENT Button fg/bg colors ***/
989   i = 0;
990   XtSetArg(arg[i], XmNbackground, &Transparent); i++;
991   XtSetArg(arg[i], XmNforeground, &transFg);     i++;
992   XtGetValues(menu1, arg, i);
993   i = 0;
994   XtSetArg(arg[i], XmNbackground, Transparent); i++;
995   XtSetArg(arg[i], XmNforeground, transFg);     i++;
996   XtSetValues(transparentColorToggle, arg, i);
997
998 /*** Store the colors in the dynamic array ***/
999
1000   DynamicPen[BG_COLOR-BG_COLOR] = Background;
1001   DynamicPen[FG_COLOR-BG_COLOR] = Foreground;
1002   DynamicPen[TS_COLOR-BG_COLOR] = TopShadow;
1003   DynamicPen[BS_COLOR-BG_COLOR] = BottomShadow;
1004   DynamicPen[SELECT_COLOR-BG_COLOR] = Select;
1005   DynamicPen[TRANS_COLOR-BG_COLOR] = Transparent;
1006
1007 #ifdef DEBUG
1008   if (debug)
1009     stat_out("Backgrounds set for all 6 dynamic colors\n");
1010 #endif
1011
1012 /*** STUB *********************************************************/
1013   DynamicMono[BG_COLOR-BG_COLOR] = black_pixel;
1014   DynamicMono[FG_COLOR-BG_COLOR] = white_pixel;
1015   DynamicMono[TS_COLOR-BG_COLOR] = white_pixel;
1016   DynamicMono[BS_COLOR-BG_COLOR] = black_pixel;
1017   DynamicMono[SELECT_COLOR-BG_COLOR] = white_pixel;
1018   DynamicMono[TRANS_COLOR-BG_COLOR] = Transparent;
1019
1020   for (i=0; i<NUM_STATICS; i++) {
1021   /*** Init the 16 color values ***/
1022     status = XParseColor(dpy, Cmap, color_table[i][5], &exact_def);
1023     if (!status) {
1024       sprintf(err_str, "%s %d",
1025               GETSTR(10,30, "Unable to parse static color no."), i+1);
1026       Abort(err_str);
1027      }
1028     status = XAllocColor(dpy, Cmap, &exact_def);
1029     if (!status) {
1030       sprintf(err_str, "%s %d",
1031               GETSTR(10,32, "Unable to allocate static color no."), i+1);
1032       Abort(err_str);
1033      }
1034     StaticPen[i] = exact_def.pixel;
1035     j = 0;
1036     XtSetArg(arg[j], XmNbackground, StaticPen[i]); j++;
1037     XtSetValues(StaticWid[i], arg, j);
1038   /*** Init the 16 monochrome values ***/
1039     status = XParseColor(dpy, Cmap, color_table[i][2], &exact_def);
1040     if (!status) {
1041       sprintf(err_str, "%s %d",
1042               GETSTR(10,30, "Unable to parse static color no."), i+1);
1043       Abort(err_str);
1044      }
1045     status = XAllocColor(dpy, Cmap, &exact_def);
1046     if (!status) {
1047       sprintf(err_str, "%s %d",
1048               GETSTR(10,32, "Unable to allocate static color no."), i+1);
1049       Abort(err_str);
1050      }
1051     StaticMono[i] = exact_def.pixel;
1052    } /* for */
1053 /******************************************************************/
1054 }
1055
1056
1057 /***************************************************************************
1058  *                                                                         *
1059  * Routine:   Init_Color_Table                                             *
1060  *                                                                         *
1061  * Purpose:   Complete initialization of the color_table used to specify   *
1062  *            color naming conventions when writing out XPM files. Then    *
1063  *            initialize the name and pixel fields for all the elements    *
1064  *            of the global array colorSymbols.                            *
1065  *                                                                         *
1066  ***************************************************************************/
1067
1068 void
1069 Init_Color_Table( void )
1070 {
1071   int i, j;
1072   XColor cval;
1073   char ***colorTable;
1074
1075   cmap_size = XDisplayCells(dpy, screen);
1076
1077 /***
1078   for (i=NUM_STATICS; i<NUM_STATICS+5; i++) {
1079     if (DynamicMono[i-NUM_STATICS] == black_pixel)
1080       color_table[i][2] = black_string;
1081     else
1082       color_table[i][2] = white_string;
1083     cval.pixel = DynamicPen[i-NUM_STATICS];
1084     XQueryColor(dpy, Cmap, &cval);
1085     sprintf(dynamic_c_str[i-NUM_STATICS], "#%04X%04X%04X",
1086                 cval.red, cval.green, cval.blue);
1087     color_table[i][5] = dynamic_c_str[i-NUM_STATICS];
1088    }
1089   color_table[NUM_PENS-1][2] = none_string;
1090
1091   cval.pixel = DynamicPen[TRANS_COLOR-BG_COLOR];
1092   XQueryColor(dpy, Cmap, &cval);
1093   sprintf(dynamic_c_str[NUM_DYNAMICS-1], "#%04X%04X%04X",
1094                 cval.red, cval.green, cval.blue);
1095   color_table[NUM_PENS-1][5] = dynamic_c_str[NUM_DYNAMICS-1];
1096 ***/
1097
1098 #ifdef DEBUG
1099   if (debug) {
1100     stat_out("XPM Color Table initialized:\n");
1101     for (i=0; i<(NUM_PENS); i++)
1102       stat_out("  %s %18s %18s\n", color_table[i][0], color_table[i][1],
1103                                 color_table[i][2]);
1104    }
1105 #endif
1106
1107   colorSymbols = (XpmColorSymbol *) XtMalloc(NUM_PENS * sizeof(XpmColorSymbol));
1108   if (!colorSymbols)
1109     Abort(GETSTR(10,38, "No memory(0)"));
1110   for (i=0; i<NUM_STATICS; i++) {
1111     colorSymbols[i].name  = (char *) XtMalloc(strlen(color_table[i][1]) +1);
1112     if (!colorSymbols[i].name)
1113       Abort(GETSTR(10,40, "No memory(1)"));
1114     strcpy(colorSymbols[i].name, color_table[i][1]);
1115     colorSymbols[i].value = "";
1116     colorSymbols[i].pixel = StaticPen[i];
1117    }
1118   for (i=NUM_STATICS; i<NUM_STATICS+NUM_DYNAMICS; i++) {
1119     colorSymbols[i].name  = (char *) XtMalloc(strlen(color_table[i][1]) +1);
1120     if (!colorSymbols[i].name)
1121       Abort(GETSTR(10,42, "No memory(2)"));
1122     strcpy(colorSymbols[i].name, color_table[i][1]);
1123     colorSymbols[i].value = "";
1124     colorSymbols[i].pixel = DynamicPen[i-NUM_STATICS];
1125    }
1126
1127 #ifdef DEBUG
1128   if (debug) {
1129     stat_out("%d Color Symbols installed:\n", NUM_PENS);
1130     for (i=0; i<NUM_PENS; i++) {
1131       stat_out("    %d - %s | %s | %d\n", (i+1), colorSymbols[i].name,
1132                         colorSymbols[i].value, colorSymbols[i].pixel);
1133      }
1134    }
1135 #endif
1136
1137 /*** now comes the ugly part, initialize the .colorTable field   ***/
1138 /*** in xpm_WriteAttribs.  This should remain constant for the   ***/
1139 /*** life of the executable, and so only needs to be initialized ***/
1140 /*** once.                                                       ***/
1141
1142   colorTable = (char ***) calloc(NUM_PENS, sizeof(char **));
1143   xpm_WriteAttribs.colorTable = (XpmColor*)colorTable;
1144   xpm_WriteAttribs.pixels = (Pixel *) calloc(NUM_PENS, sizeof(Pixel));
1145   if (!xpm_WriteAttribs.colorTable)
1146     Abort(GETSTR(10,44, "No memory(3)"));
1147   for (i=0; i<NUM_PENS; i++) {
1148     colorTable[i] = (char **) calloc(6, sizeof(char *));
1149     if (!colorTable[i])
1150       Abort(GETSTR(10,46, "No memory(4)"));
1151    } /* for(i...) */
1152   for (i=0; i<NUM_PENS; i++) {
1153     xpm_WriteAttribs.pixels[i] = colorSymbols[i].pixel;
1154     for (j=0; j<6; j++) {
1155       if (color_table[i][j] && strlen(color_table[i][j]) > 0) {
1156         colorTable[i][j] = (char *) XtMalloc(strlen(color_table[i][j])+1);
1157         if (!colorTable[i][j])
1158           Abort(GETSTR(10,48, "No memory(5)"));
1159         strcpy(colorTable[i][j], color_table[i][j]);
1160        } /* if */
1161      } /* for(j...) */
1162    } /* for(i...) */
1163   xpm_WriteAttribs.ncolors = NUM_PENS;
1164   xpm_WriteAttribs.hints_cmt = hints_cmt;
1165   xpm_WriteAttribs.colors_cmt = colors_cmt;
1166   xpm_WriteAttribs.pixels_cmt = pixels_cmt;
1167   xpm_WriteAttribs.mask_pixel = 0x80000000;
1168
1169 #ifdef DEBUG
1170   if (debug)
1171     Dump_AttribStruct(&xpm_WriteAttribs);
1172 #endif
1173 }
1174
1175
1176 /***************************************************************************
1177  *                                                                         *
1178  * Routine:   Size_IconForm                                                *
1179  *                                                                         *
1180  * Purpose:   Given new dimensions for the Color and Mono icon widgets,    *
1181  *            calculate and set the new overall dimensions for the icon    *
1182  *            form widget (iconForm) which holds both of them and their    *
1183  *            labels.                                                      *
1184  *                                                                         *
1185  ***************************************************************************/
1186
1187 void
1188 Size_IconForm(
1189         Dimension width,
1190         Dimension height )
1191 {
1192   Arg args[10];
1193   int i, top_offset;
1194   Dimension label1_w, label1_h, label2_w, label2_h;
1195   Dimension form_width, form_height, junk;
1196   XmString label1_str, label2_str;
1197   XmFontList label_fontlist;
1198   Position diff;
1199
1200 #ifdef DEBUG
1201   if (debug)
1202     stat_out("Entering Size_IconForm\n");
1203 #endif
1204
1205 /*********************************************************************
1206  * Before re-sizing the 2 icons (up or down), make sure their parent *
1207  * form's width is at least wide enough to fully show the two label  *
1208  * gadgets (iconSize and monoLabel).  If the icon widths are smaller *
1209  * than this, set offsets to center them on the space provided.      *
1210  *********************************************************************/
1211
1212 /*********************************************************************
1213  * First, get the minimum usable widths for the two label gadgets,   *
1214  * and their current heights.                                        *
1215  *********************************************************************/
1216   i = 0;
1217   XtSetArg(args[i], XmNfontList, &label_fontlist); i++;
1218   XtSetArg(args[i], XmNlabelString, &label1_str); i++;
1219   XtGetValues(iconSize, args, i);
1220   i = 0;
1221   XtSetArg(args[i], XmNlabelString, &label2_str); i++;
1222   XtGetValues(monoLabel, args, i);
1223
1224   XmStringExtent(label_fontlist, label1_str, &label1_w, &junk);
1225   XmStringExtent(label_fontlist, label2_str, &label2_w, &junk);
1226   i = 0;
1227   XtSetArg(args[i], XmNheight, &label1_h); i++;
1228   XtGetValues(iconSize, args, i);
1229   i = 0;
1230   XtSetArg(args[i], XmNheight, &label2_h); i++;
1231   XtGetValues(monoLabel, args, i);
1232
1233 /*********************************************************************
1234  * If the min. width for either label gadget is greater than the     *
1235  * current icon widths, use half the difference between the two      *
1236  * widths as a left and right offset for the two icon (drawn button) *
1237  * widgets.                                                          *
1238  *********************************************************************/
1239   if ((label1_w > width) || (label2_w > width))
1240     diff = (Position) (((label1_w > label2_w) ? label1_w : label2_w)
1241                 - width) / 2;
1242   else
1243     diff = 0;
1244
1245   i = 0;
1246   XtSetArg(args[i], XmNleftOffset, diff); i++;
1247   XtSetValues(iconImage, args, i);
1248   XtSetValues(monoImage, args, i);
1249
1250 /*********************************************************************
1251  * The overall form dimensions should be as follows: the form width  *
1252  * will be the greater of the icon widths, or the widths of the two  *
1253  * label gadgets.  The form height will be the sum of the two icon   *
1254  * heights, plus the sum of heights of the two label gadgets, plus   *
1255  * the vertical offset between the bottom of the first label and the *
1256  * top of the second icon.                                           *
1257  *********************************************************************/
1258   i = 0;
1259   XtSetArg(args[i], XmNtopOffset, &top_offset); i++;
1260   XtGetValues(monoImage, args, i);
1261   form_width  = max(width, (Dimension)max(label1_w, label2_w));
1262   form_height = (height*2) + label1_h + label2_h + top_offset;
1263 #ifdef DEBUG
1264   if (debug) {
1265     stat_out("  form_width = %d (of %d,%d,%d)\n", form_width, width, label1_w,
1266                 label2_w);
1267     stat_out("  form_height = %d\n", form_height);
1268    }
1269 #endif
1270   i = 0;
1271   XtSetArg(args[i], XmNwidth, form_width); i++;
1272   XtSetArg(args[i], XmNheight, form_height); i++;
1273   XtSetValues(iconForm, args, i);
1274
1275 #ifdef DEBUG
1276   if (debug)
1277     stat_out("Leaving Size_IconForm\n");
1278 #endif
1279 }
1280
1281
1282 /***************************************************************************
1283  *                                                                         *
1284  * Routine:   Init_Icons                                                   *
1285  *                                                                         *
1286  * Purpose:   Initialize new color and mono icons at program start-up      *
1287  *            and at the following times:                                  *
1288  *              o When 'New' is selected from the 'File' pull-down menu.   *
1289  *              o When 'Resize Icon' is selected from the 'Edit' pull-down *
1290  *                menu.                                                    *
1291  *              o When 'Load' is selected from the 'File' pull-down menu,  *
1292  *                and a new file is read in.                               *
1293  *              o When 'Grab Screen Image' is selected from the 'Edit'     *
1294  *                pull-down menu, and the image is loaded into the editor. *
1295  *                                                                         *
1296  *            This routine sizes the iconImage, monoImage, and tablet      *
1297  *            widgets to the new dimensions (*MagFactor, and +1 in the     *
1298  *            case of the tablet widget).  It also creates the application-*
1299  *            internal Pixmaps associated with the iconImage and monoImage.*
1300  *            If the 'saveFlag' flag is 'True', it is assumed that the     *
1301  *            current icons are being resized and that there are existing  *
1302  *            images that need to be retained.  In this case, the new      *
1303  *            Pixmaps are created and the old Pixmaps are copied onto the  *
1304  *            new ones, before the old Pixmaps are freed.                  *
1305  *                                                                         *
1306  ***************************************************************************/
1307
1308 void
1309 Init_Icons(
1310         Dimension width,
1311         Dimension height,
1312         Boolean saveFlag )
1313 {
1314   Pixmap tmpPix;
1315   Pixmap tmp_color, tmp_mono;
1316   char text[40];
1317   Arg args[10];
1318   int i, x_offset, y_offset;
1319   XmString local_str;
1320
1321 #ifdef DEBUG
1322   if (debug)
1323     stat_out("Entering Init_Icons: flag=%d\n", saveFlag);
1324     stat_out("         Init_Icons: color=%x mono=%x\n", color_icon, mono_icon);
1325 #endif
1326
1327   tmp_color = NULL;
1328   tmp_mono = NULL;
1329
1330 /*** App. init or 'New Icon' ***/
1331   if (!saveFlag) {
1332     if (color_icon)
1333       XFreePixmap(dpy, color_icon);
1334     if (mono_icon)
1335       XFreePixmap(dpy, mono_icon);
1336    }
1337 /*** Resizing the existing icon ***/
1338   else {
1339     if (color_icon)
1340       tmp_color = color_icon;
1341     if (mono_icon)
1342       tmp_mono = mono_icon;
1343     x_offset = 0;
1344     y_offset = 0;
1345    }
1346
1347   color_icon = XCreatePixmap(dpy, root, width, height,
1348                                 DefaultDepth(dpy, screen));
1349   mono_icon = XCreatePixmap(dpy, root, width, height,
1350                                 DefaultDepth(dpy, screen));
1351
1352   if ((color_icon == NULL) || (mono_icon == NULL))
1353     Abort(GETSTR(10,50, "Cannot initialize application icon storage"));
1354
1355   XSetForeground(dpy, scratch_gc, Transparent);
1356   XFillRectangle(dpy, color_icon, scratch_gc, 0, 0, width, height);
1357   XFillRectangle(dpy, mono_icon, scratch_gc, 0, 0, width, height);
1358
1359   sprintf(text, "%d x %d", width, height);
1360   i = 0;
1361   local_str = XmStringCreateLocalized(text);
1362   XtSetArg(args[i], XmNlabelString, local_str); i++;
1363   XtSetValues(iconSize, args, i);
1364   XmStringFree(local_str);
1365
1366   i = 0;
1367   XtSetArg(args[i], XmNwidth, width); i++;
1368   XtSetArg(args[i], XmNheight, height); i++;
1369   XtSetValues(iconImage, args, i);
1370   XtSetValues(monoImage, args, i);
1371
1372 /*********************************************************************
1373  * Call Size_IconForm() to re-do the layout of the iconForm widget,  *
1374  * which contains the iconImage, iconSize, monoImage, and monoLabel  *
1375  * widgets.                                                          *
1376  *********************************************************************/
1377
1378   Size_IconForm(width, height);
1379
1380   if (saveFlag) {
1381     XCopyArea(dpy, tmp_color, color_icon, Color_gc, 0, 0,
1382                 icon_width, icon_height, x_offset, y_offset);
1383     XCopyArea(dpy, tmp_mono, mono_icon, Mono_gc, 0, 0,
1384                 icon_width, icon_height, x_offset, y_offset);
1385     if (tmp_color)
1386       XFreePixmap(dpy, tmp_color);
1387     if (tmp_mono)
1388       XFreePixmap(dpy, tmp_mono);
1389    }
1390
1391   if (XtWindow(iconImage))
1392     XCopyArea(dpy, color_icon, XtWindow(iconImage), Color_gc,
1393                 0, 0, width, height, 0, 0);
1394   if (XtWindow(monoImage))
1395     XCopyArea(dpy, mono_icon, XtWindow(monoImage), Mono_gc,
1396                 0, 0, width, height, 0, 0);
1397   i = 0;
1398   XtSetArg(args[i], XmNwidth, ((width*MagFactor)+1)); i++;
1399   XtSetArg(args[i], XmNheight, ((height*MagFactor)+1)); i++;
1400   XtSetValues(tablet_wid, args, i);
1401
1402   icon_width  = width;
1403   icon_height = height;
1404
1405 /* This code does not seem to be needed and since it slows down
1406    the grid drawing I'll take it out for now*/
1407 /*
1408   if (tablet_win)
1409      Repaint_Exposed_Tablet();
1410 */
1411
1412 #ifdef DEBUG
1413   if (debug)
1414     stat_out("Leaving Init_Icons\n");
1415 #endif
1416 }
1417
1418 static void
1419 TransferCallback(
1420         Widget w,
1421         XtPointer client_data,
1422         XtPointer call_data)
1423 {
1424         DtDndTransferCallback transferInfo = (DtDndTransferCallback) call_data;
1425
1426         if (transferInfo->reason == DtCR_DND_TRANSFER &&
1427             transferInfo->operation == XmDROP_COPY) {
1428
1429                 Process_DropCheckOp(w, client_data, call_data);
1430         } else {
1431                 transferInfo->status = DtDND_FAILURE;
1432         }
1433 }
1434
1435 static void
1436 AnimateCallback(
1437         Widget w,
1438         XtPointer client_data,
1439         XtPointer call_data)
1440 {
1441    DtDndDropAnimateCallbackStruct *animateInfo =
1442         (DtDndDropAnimateCallbackStruct *) call_data;
1443
1444    if (animateInfo->reason == DtCR_DND_DROP_ANIMATE) {
1445
1446       Process_DropOp(w, client_data, call_data);
1447    }
1448 }
1449
1450 /***************************************************************************
1451  *                                                                         *
1452  * Routine:   RegisterDropSites                                            *
1453  *                                                                         *
1454  * Purpose:   Register the tablet as a valid drop zone.                    *
1455  *                                                                         *
1456  ***************************************************************************/
1457
1458 void
1459 RegisterDropSites( void )
1460 {
1461     static XtCallbackRec transferCB[] = { {TransferCallback, NULL},
1462                                                {NULL, NULL} };
1463     static XtCallbackRec animateCB[] = { {AnimateCallback, NULL},
1464                                                {NULL, NULL} };
1465     Arg args[3];
1466     int n;
1467     Widget clipWin;
1468
1469     XtSetArg(args[0], XmNclipWindow, &clipWin);
1470     XtGetValues(viewport, args, 1);
1471
1472     /*
1473      * This code makes assumptions about the order of the arguments.
1474      * XmNanimationStyle is assumed to be first and
1475      * DtNregisterChildren is assumed to be last
1476      */
1477     n = 0;
1478     XtSetArg(args[n], XmNanimationStyle, XmDRAG_UNDER_NONE);  n++; /* first */
1479     XtSetArg(args[n], DtNdropAnimateCallback, animateCB);  n++;
1480     XtSetArg(args[n], DtNregisterChildren, True);  n++; /* last */
1481
1482     DtDndDropRegister(clipWin, DtDND_FILENAME_TRANSFER, XmDROP_COPY,
1483                    (XtCallbackList) transferCB, args, n);
1484
1485     DtDndDropRegister(tabletBorder, DtDND_FILENAME_TRANSFER, XmDROP_COPY,
1486                    (XtCallbackList) transferCB, args, n);
1487
1488     DtDndDropRegister(tabletFrame, DtDND_FILENAME_TRANSFER, XmDROP_COPY,
1489                    (XtCallbackList) transferCB, args, n);
1490
1491     DtDndDropRegister(tablet, DtDND_FILENAME_TRANSFER, XmDROP_COPY,
1492                    (XtCallbackList) transferCB, args, n - 1);
1493
1494     /*
1495      * Once the drag and drop library is fixed, the following calls
1496      * will not be necessary. Currently the dnd library does not pass on
1497      * Motif resource values, in this case XmNanimationStyle.
1498      */
1499
1500     XmDropSiteUpdate(clipWin, args, 1);
1501     XmDropSiteUpdate(tabletBorder, args, 1);
1502     XmDropSiteUpdate(tabletFrame, args, 1);
1503     XmDropSiteUpdate(tablet, args, 1);
1504 }
1505
1506 /***************************************************************************
1507  *                                                                         *
1508  * Routine:   Abort                                                        *
1509  *                                                                         *
1510  * Purpose:   Print a fatal error message and then exit.                   *
1511  *                                                                         *
1512  ***************************************************************************/
1513
1514 void
1515 Abort(
1516         char *str )
1517
1518 {
1519   _DtSimpleError (progName, DtError, NULL, str, NULL);
1520   exit(-1);
1521 }
1522
1523
1524 /***************************************************************************
1525  *                                                                         *
1526  * Routine:   stat_out                                                     *
1527  *                                                                         *
1528  * Purpose:   Generate a debug message to stderr.  Flush stdout, and then  *
1529  *            print the message(s) to stderr and flush stderr.  By doing   *
1530  *            an fflush after each fprintf, we can always determin where   *
1531  *            in the code the process is running.  The stat_out() routine  *
1532  *            is invoked like printf() with up to 7 arguments.  It is      *
1533  *            source-code identical to the outl() routine used in the xwd  *
1534  *            and xwud utilities which are part of standard X11.           *
1535  *                                                                         *
1536  *X11***********************************************************************/
1537
1538 void
1539 stat_out(
1540         char *msg,
1541         char *arg0,
1542         char *arg1,
1543         char *arg2,
1544         char *arg3,
1545         char *arg4,
1546         char *arg5,
1547         char *arg6 )
1548 {
1549 /* static char str[1024]; */
1550
1551         fflush(stdout);
1552         fprintf(stderr, msg, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
1553         fflush(stderr);
1554
1555 /*        sprintf(str, msg, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
1556           _DtSimpleError ("dticon-stat_out", DtError, NULL, str, NULL);*/
1557 }
1558
1559 /***************************************************************************
1560  *                                                                         *
1561  * Routine:   PixelTableClear                                              *
1562  *                                                                         *
1563  * Purpose:   Reset the pixel table to force subsequent lookups to get     *
1564  *            new pixel information.  Do not free up space for table.      *
1565  *                                                                         *
1566  *X11***********************************************************************/
1567 void
1568 PixelTableClear()
1569 {
1570     pixelTable.numItems = 0;
1571     pixelTable.lastFound = 0;
1572 }
1573
1574 /***************************************************************************
1575  *                                                                         *
1576  * Routine:   PixelTableLookup                                             *
1577  *                                                                         *
1578  * Purpose:   Return index into the Pixel Table for the pixel passed in.   *
1579  *            If the pixel passed in isn't already in the table, it will   *
1580  *            be added.  This may require allocating a larger pixel table. *
1581  *            In order to clear the Pixel Table (which should be done each *
1582  *            time a new image is being processed in order to get current  *
1583  *            pixel data) call PixelTableClear().                          *
1584  *                                                                         *
1585  *            For performance, save the last lookup result, and check it   *
1586  *            first.  This should improve performance unless image is very *
1587  *            "dithered".  The allocNew parameter will be set if the image *
1588  *            was grabbed from screen.  In this case, each "screen" pixel  *
1589  *            will need a new pixel allocated for it.                      *
1590  *                                                                         *
1591  *X11***********************************************************************/
1592 int
1593 PixelTableLookup(
1594         Pixel pixelIn,
1595         Boolean allocNew )
1596 {
1597     int i, grayValue;
1598     XColor tmpXColor;
1599
1600     /** first, check to see if the last lookup was for the same pixel **/
1601     if (pixelTable.lastFound < pixelTable.numItems)
1602         if (pixelTable.item[pixelTable.lastFound].xcolor.pixel == pixelIn)
1603             return pixelTable.lastFound;
1604
1605     /** look through table to see if there is an entry for this pixel **/
1606     for (i=0; i<pixelTable.numItems; i++)
1607     {
1608         if (pixelTable.item[i].xcolor.pixel == pixelIn)
1609         {
1610             pixelTable.lastFound = i;
1611             return i;
1612         }
1613     }
1614
1615     /**                                     **/
1616     /** No entry for this pixel, create one **/
1617     /**                                     **/
1618
1619     /** Allocate larger table if needed     **/
1620     if (pixelTable.numItems == pixelTable.pixelTableSize)
1621     {
1622         pixelTable.pixelTableSize += PIXEL_TABLE_INC;
1623         pixelTable.item = (PixelTableItem *)XtRealloc((char *)pixelTable.item,
1624                               sizeof(PixelTableItem)*pixelTable.pixelTableSize);
1625     }
1626
1627     /** Get color information for pixelIn   **/
1628     i = pixelTable.numItems;
1629     pixelTable.numItems++;
1630
1631     pixelTable.item[i].xcolor.pixel = pixelIn;
1632     XQueryColor(dpy, Cmap, &(pixelTable.item[i].xcolor));
1633
1634     /*---          < ESTABLISH THE GREYSCALE IMAGE >            ---*/
1635     /*--- The NTSC formula for converting an RGB value into the ---*/
1636     /*--- corresponding grayscale value is:                     ---*/
1637     /*--- luminosity = .299 red + .587 green + .114 blue        ---*/
1638
1639     grayValue = ( (int)((pixelTable.item[i].xcolor.red*299) +
1640                    (pixelTable.item[i].xcolor.green*587) +
1641                    (pixelTable.item[i].xcolor.blue*114)) / 1000) >> 8;
1642
1643     if (grayValue < GAMMA_CUTOFF)
1644         pixelTable.item[i].mono = black_pixel;
1645     else
1646         pixelTable.item[i].mono = white_pixel;
1647
1648     /** Allocate new color cell if needed (use old for mono conversion) **/
1649     if (allocNew)
1650     {
1651         tmpXColor.red = pixelTable.item[i].xcolor.red;
1652         tmpXColor.green = pixelTable.item[i].xcolor.green;
1653         tmpXColor.blue = pixelTable.item[i].xcolor.blue;
1654
1655         if (!XAllocColor(dpy, Cmap, &tmpXColor))
1656         {
1657             /* for lack of something better, use the old color cell */
1658             pixelTable.item[i].newCell = pixelTable.item[i].xcolor.pixel;
1659             DoErrorDialog(GETSTR(10,62,"Operation failed.\nColormap is full"));
1660         }
1661         else
1662             pixelTable.item[i].newCell = tmpXColor.pixel;
1663     }
1664
1665     pixelTable.lastFound = i;
1666     return i;
1667 }
1668
1669
1670 /***************************************************************************
1671  *                                                                         *
1672  * Routine:   Switch_FillSolids                                            *
1673  *                                                                         *
1674  * Purpose:   Toggles the state of the global FillSolids flag, based on    *
1675  *            the XmNset resource for the fillToggle widget.               *
1676  *                                                                         *
1677  *X11***********************************************************************/
1678
1679 void
1680 Switch_FillSolids( void )
1681 {
1682   Arg args[10];
1683   int i;
1684
1685   i = 0;
1686   XtSetArg(args[i], XmNset, &FillSolids); i++;
1687   XtGetValues(fillToggle, args, i);
1688   if (FillSolids)
1689     Set_Gfx_Labels(FILL);
1690   else
1691     Set_Gfx_Labels(HOLLOW);
1692 #ifdef DEBUG
1693   if (debug)
1694     stat_out("Fill_Solids toggle = %s\n", (FillSolids? "True" : "False"));
1695 #endif
1696 }
1697
1698
1699 /***************************************************************************
1700  *                                                                         *
1701  * Routine:   Select_New_Pen                                               *
1702  *                                                                         *
1703  * Purpose:   Changes the fg color of the pen GC, based on the parameter   *
1704  *            passed in.                                                   *
1705  *                                                                         *
1706  *X11***********************************************************************/
1707
1708 int
1709 Select_New_Pen(
1710         int n )
1711 {
1712   int new_block, new_pen;
1713
1714   if (n < BG_COLOR) {
1715     new_block = STATIC_COLOR;
1716     new_pen   = n;
1717    }
1718   else {
1719     new_block = DYNAMIC_COLOR;
1720     new_pen   = n - BG_COLOR;
1721    }
1722 #ifdef DEBUG
1723   if (debug) {
1724     stat_out("**** n = %d, new_block = %d, new_pen = %d\n", n,
1725                         new_block, new_pen);
1726    }
1727 #endif
1728
1729 /*** if the new choice is the current pen, re-set it and return ***/
1730   if ((new_block == ColorBlock) && (new_pen == CurrentColor)) {
1731     if (new_block == STATIC_COLOR)
1732       XmToggleButtonSetState(StaticWid[new_pen], True, False);
1733     else
1734       XmToggleButtonSetState(DynamicWid[new_pen], True, False);
1735     return;
1736    }
1737
1738 /*** un-set the previous choice ***/
1739   if (ColorBlock == STATIC_COLOR)
1740     XmToggleButtonSetState(StaticWid[CurrentColor], False, False);
1741   else
1742     XmToggleButtonSetState(DynamicWid[CurrentColor], False, False);
1743
1744 #ifdef DEBUG
1745   if (debug)
1746     stat_out("  New pen color = %d\n", n);
1747 #endif
1748
1749   ColorBlock = new_block;       /*** STATIC or DYNAMIC? ***/
1750   CurrentColor = new_pen;       /*** index w/i the appropriate block ***/
1751
1752   XSetForeground(dpy, Color_gc,
1753         (ColorBlock ? DynamicPen[CurrentColor] : StaticPen[CurrentColor]));
1754   XSetForeground(dpy, Mono_gc,
1755         (ColorBlock ? DynamicMono[CurrentColor] : StaticMono[CurrentColor]));
1756 }
1757
1758
1759 /***************************************************************************
1760  *                                                                         *
1761  * Routine:   Backup_Icons                                                 *
1762  *                                                                         *
1763  * Purpose:   Copy the current contents of the color and mono icons to     *
1764  *            their undo storage areas, just prior to modifying them with  *
1765  *            the current graphics operation.                              *
1766  *                                                                         *
1767  *X11***********************************************************************/
1768
1769 void
1770 Backup_Icons( void )
1771 {
1772 /*** If we're backing up the tablet contents, it's dirty ***/
1773 /*** and may need to be saved to file at some point.     ***/
1774
1775   Dirty = True;
1776
1777 /*** if the icon sizes don't match the backup sizes, or  ***/
1778 /*** either of the backup icons don't exist, create them ***/
1779
1780   if ((icon_width != backup_width)   ||
1781       (icon_height != backup_height) ||
1782       (!prev_color_icon) ||
1783       (!prev_mono_icon)) {
1784     if (prev_color_icon)
1785       XFreePixmap(dpy, prev_color_icon);
1786     if (prev_mono_icon)
1787       XFreePixmap(dpy, prev_mono_icon);
1788     prev_color_icon = XCreatePixmap(dpy, root, icon_width, icon_height,
1789                                 DefaultDepth(dpy, screen));
1790     prev_mono_icon = XCreatePixmap(dpy, root, icon_width, icon_height,
1791                                 DefaultDepth(dpy, screen));
1792     backup_width = icon_width;
1793     backup_height = icon_height;
1794    }
1795
1796 /*** now, copy the color and mono pixmap to the backup pixmaps ***/
1797
1798   XCopyArea(dpy, color_icon, prev_color_icon,
1799         Color_gc, 0, 0, icon_width, icon_height, 0, 0);
1800   XCopyArea(dpy, mono_icon, prev_mono_icon,
1801         Mono_gc, 0, 0, icon_width, icon_height, 0, 0);
1802   UndoFlag = True;
1803   XtSetSensitive( editMenu_undo_pb, True);
1804 }
1805
1806
1807 /***************************************************************************
1808  *                                                                         *
1809  * Routine:   DoErrorDialog                                                *
1810  *                                                                         *
1811  * Purpose:   Some error has just occurred in the application.  Pop up     *
1812  *            the error dialog and display the message passed in.          *
1813  *                                                                         *
1814  *X11***********************************************************************/
1815
1816 void
1817 DoErrorDialog(
1818         char *str )
1819 {
1820   int i;
1821   Arg arg[10];
1822   XmString local_str;
1823
1824   i = 0;
1825   local_str = XmStringCreateLocalized(str);
1826   XtSetArg(arg[i], XmNmessageString, local_str);
1827   i++;
1828   XtSetValues(stdErrDialog, arg, i);
1829   XmStringFree(local_str);
1830   XtManageChild(stdErrDialog);
1831 }
1832
1833
1834 /***************************************************************************
1835  *                                                                         *
1836  * Routine:   DoQueryDialog                                                *
1837  *                                                                         *
1838  * Purpose:   The user should be prompted on an action they're attempting. *
1839  *            Pop up the query dialog and display the message passed in.   *
1840  *                                                                         *
1841  *X11***********************************************************************/
1842
1843 void
1844 DoQueryDialog(
1845         char *str )
1846 {
1847   int i;
1848   Arg arg[10];
1849   XmString local_str;
1850   static Widget w=NULL;
1851
1852   XtPopup(dtIconShell, XtGrabNone);
1853   XMapRaised(XtDisplay(dtIconShell), XtWindow(dtIconShell));
1854
1855   if (!w)
1856     w = XmMessageBoxGetChild(queryDialog, XmDIALOG_CANCEL_BUTTON);
1857
1858   i = 0;
1859   local_str = XmStringCreateLocalized(str);
1860   XtSetArg(arg[i], XmNmessageString, local_str); i++;
1861   XtSetValues(queryDialog, arg, i);
1862   XmStringFree(local_str);
1863   XtManageChild(queryDialog);
1864
1865   XmProcessTraversal(w, XmTRAVERSE_CURRENT);
1866 }
1867
1868
1869 /***************************************************************************
1870  *                                                                         *
1871  * Routine:   Do_GrabOp                                                    *
1872  *                                                                         *
1873  * Purpose:   Switch to GRAB mode.  Grab the server and the pointer until  *
1874  *            the user has made a selection from the screen.  The server   *
1875  *            and pointer are ungrabbed in Do_ButtonOp().                  *
1876  *                                                                         *
1877  *      Note: Moved the server grab until the mouse button is pressed      *
1878  *            (beginning the screen grab) in order to give the windows     *
1879  *            time to repaint.  This was needed specifically for the       *
1880  *            queryDialog used when the icon image is "Dirty".             *
1881  *                                                                         *
1882  *X11***********************************************************************/
1883
1884 void
1885 Do_GrabOp( void )
1886 {
1887   Backup_G_Op = GraphicsOp;
1888   GraphicsOp  = S_GRAB;
1889   cursor = XCreateFontCursor(dpy, XC_crosshair);
1890   XGrabPointer(dpy, root, False,
1891                  ButtonPressMask|PointerMotionMask|ButtonReleaseMask,
1892                  GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
1893 }
1894
1895
1896 /***************************************************************************
1897  *                                                                         *
1898  * Routine:   LoadGrabbedImage                                             *
1899  *                                                                         *
1900  * Purpose:   Given an [x,y] coordinate, plus width and height, grab an    *
1901  *            XImage from the Root window and load it into the icon        *
1902  *            editor.                                                      *
1903  *                                                                         *
1904  *X11***********************************************************************/
1905 int
1906 LoadGrabbedImage(
1907         int x,
1908         int y,
1909         int width,
1910         int height )
1911 {
1912   XImage *img, *mono_img;
1913   int i, j;
1914   int pixelTableIndex;
1915
1916 #ifdef DEBUG
1917   if (debug)
1918     stat_out("LoadGrabbedImage: [%d,%d] - width: %d,  height: %d\n",
1919                 x, y, width, height);
1920 #endif
1921
1922   img = NULL;
1923
1924   if (width > 0 && height > 0)
1925     img = XGetImage(dpy, root, x, y, width, height, AllPlanes, format);
1926
1927   XUngrabPointer (dpy, CurrentTime);
1928   XUngrabServer (dpy);
1929   XSync (dpy, False);
1930
1931   if (!img) {
1932     DoErrorDialog( GETSTR(10,60, "Screen image capture failed") );
1933     return(False);
1934   }
1935
1936 /*********************************************************************
1937  * OK, now that we've got the image, we need to convert the entire   *
1938  * thing to pixels that the icon editor won't lose control over.     *
1939  * To do this, we find all the pixel values in the image and request *
1940  * equivalent read-only colors in the colormap (we won't be drawing  *
1941  * with any pen colors we don't already have).  Once the requests to *
1942  * the Cmap have been honored, we go thru the image one more time    *
1943  * and replace each old pixel with the correct new value.            *
1944  * NOTE: Old code assumed 256 max colors... NOT OKAY.  Added dynamic *
1945  *       pixel table for color lookup, which also handles allocating *
1946  *       the new read-only color. - julie                            *
1947  *********************************************************************/
1948
1949 /*********************************************************************
1950  * Dup the XImage so there'll be two identical copies: one to        *
1951  * update with the new color values, and one with which to create    *
1952  * a monochrome equivalent.                                          *
1953  *********************************************************************/
1954   mono_img = XSubImage(img, 0, 0, img->width, img->height);
1955   if (!mono_img) {
1956     DoErrorDialog( GETSTR(10,60, "Screen image capture failed") );
1957     return(False);
1958    }
1959
1960   /* force new pixel lookup, in case pixel data has changed */
1961   PixelTableClear();
1962   for (i=0; i<img->width; i++)
1963   {
1964     for (j=0; j<img->height; j++)
1965     {
1966       pixelTableIndex = PixelTableLookup(XGetPixel(img, i, j), True);
1967       XPutPixel(img, i, j, PIXEL_TABLE_NEW_CELL(pixelTableIndex));
1968       XPutPixel(mono_img, i, j, PIXEL_TABLE_MONO(pixelTableIndex));
1969     }
1970   }
1971
1972   Backup_Icons();
1973   Init_Icons(img->width, img->height, DO_NOT_SAVE);
1974   XPutImage(dpy, color_icon, Color_gc, img, 0, 0, 0, 0,
1975                         img->width, img->height);
1976   XPutImage(dpy, mono_icon, Mono_gc, mono_img, 0, 0, 0, 0,
1977                         img->width, img->height);
1978
1979   XDestroyImage(img);
1980   XDestroyImage(mono_img);
1981
1982   return(True);
1983 }
1984
1985
1986 /***************************************************************************
1987  *                                                                         *
1988  * Routine:   ParseAppArgs                                                 *
1989  *                                                                         *
1990  * Purpose:   Parse the invocation arguments, looking for '-f' and '-x'.   *
1991  *            This routine is invoked once by dticon.                     *
1992  *                                                                         *
1993  *            Each of the args should be accompanied by a parameter.  If   *
1994  *            one does not exist, abort dticon with the appropriate       *
1995  *            error message.  Otherwise, store the parameter in a global   *
1996  *            variable for processing by ProcessAppArgs() (called once     *
1997  *            from event.c).                                               *
1998  *                                                                         *
1999  *X11***********************************************************************/
2000
2001 void
2002 ParseAppArgs(
2003         int num,
2004         char *cmd[] )
2005 {
2006   int i;
2007   char *cmd_arg;
2008
2009 #ifdef DEBUG
2010   if (debug)
2011     stat_out("Entering ParseAppArgs\n");
2012 #endif
2013
2014   for (i=0; i<NUM_PARAMS; i++)
2015     param_flag[i] = False;
2016   argsNeedProcessed = False;
2017
2018 /*** First, figure out which arguments get used ***/
2019
2020   /* don't process command line args if restoring from a session file */
2021   if (xrdb.session != NULL)
2022     argsNeedProcessed = True;
2023   else
2024   {
2025     for (i=1; i<num; i++)
2026     {
2027       cmd_arg = cmd[i];
2028
2029       if (cmd_arg[0] == '-')          /* process command line switches */
2030       {
2031         switch (cmd_arg[1])
2032         {
2033             case 'f':
2034               if (++i < num) {
2035                 if (strncpy(start_file, cmd[i], 255)) {
2036                   param_flag[AUTO_FILE] = True;
2037                   argsNeedProcessed = True;
2038                 }
2039                 else
2040                   Abort(GETSTR(10,52, "Invalid use of the '-f' parameter"));
2041               }
2042               else
2043                 Abort(GETSTR(10,52, "Invalid use of the '-f' parameter"));
2044               continue;
2045             case 'x': if (++i < num)
2046               {
2047                 if (strcpy(start_size, cmd[i])) {
2048                   param_flag[AUTO_SIZE] = True;
2049                   argsNeedProcessed = True;
2050                 }
2051                 else
2052                   Abort(GETSTR(10,54, "Invalid use of the '-x' parameter"));
2053               }
2054               else
2055                 Abort(GETSTR(10,54, "Invalid use of the '-x' parameter"));
2056               continue;
2057         } /* switch */
2058       } /* if */
2059     } /* for */
2060   } /* if */
2061
2062
2063 #ifdef DEBUG
2064   if (debug) {
2065     for (i=0; i<NUM_PARAMS; i++)
2066       stat_out("  param_flag = %s\n", (param_flag[i] ? "True" : "False"));
2067     stat_out("Leaving ParseAppArgs\n");
2068    }
2069 #endif
2070
2071 }
2072
2073
2074 /***************************************************************************
2075  *                                                                         *
2076  * Routine:   ProcessAppArgs                                               *
2077  *                                                                         *
2078  * Purpose:   Process the invocation arguments, '-f'and '-x'               *
2079  *                                                                         *
2080  *            If '-f' exists, the following parameter should be the name   *
2081  *            of a file to load at application start-up.  Invoke the       *
2082  *            Read_File() routine with that parameter.                     *
2083  *                                                                         *
2084  *            If '-x' exists, the following parameter should be the        *
2085  *            initial geometry for the icon tablet (work area).  Parse     *
2086  *            the string with XParseGeometry and pass the results (if      *
2087  *            valid) to Eval_NewSize().                                    *
2088  *                                                                         *
2089  *X11***********************************************************************/
2090
2091 #define MASK (WidthValue & HeightValue)
2092
2093 void
2094 ProcessAppArgs( void )
2095 {
2096   int result;
2097   int x_ret, y_ret;
2098
2099 #ifdef DEBUG
2100   if (debug)
2101     stat_out("Entering ProcessAppArgs\n");
2102 #endif
2103
2104   argsNeedProcessed = False;
2105
2106 /*** Attempt to honor the arguments, in order of priority            ***/
2107 /*** ('-session', '-f', '-x', in that order).                        ***/
2108 /***                                                                 ***/
2109 /*** GetSessionInfo() will already set start_file if needed          **/
2110
2111   if ( param_flag[AUTO_FILE] || (session.useSession && start_file[0] != '\0') )
2112   {
2113     fileIOMode = FILE_READ;
2114     if (!Read_File(start_file))
2115       DoErrorDialog( GETSTR(16,2,
2116                     "The file cannot be accessed\nor contains invalid data") );
2117     else {
2118       if (successFormat == FORMAT_XPM) {
2119         X_Hot = xpm_ReadAttribs.x_hotspot;
2120         Y_Hot = xpm_ReadAttribs.y_hotspot;
2121         Display_XPMFile(xpm_ReadAttribs.width, xpm_ReadAttribs.height);
2122       }
2123       else if (successFormat == FORMAT_XBM) {
2124         X_Hot = x_hot;
2125         Y_Hot = y_hot;
2126         Display_XBMFile(width_ret, height_ret);
2127       }
2128     } /* else */
2129   }
2130   else if(param_flag[AUTO_SIZE]) {
2131     result = XParseGeometry(start_size, &x_ret, &y_ret,
2132                             &width_ret, &height_ret);
2133     if ((!MASK) & result)
2134       Abort(GETSTR(10,64, "Invalid dimension parameter"));
2135     DialogFlag = NEW;
2136     Eval_NewSize(width_ret, height_ret);
2137   }
2138
2139 #ifdef DEBUG
2140   if (debug)
2141     stat_out("Leaving ProcessAppArgs\n");
2142 #endif
2143
2144 }
2145
2146
2147 /***************************************************************************
2148  *                                                                         *
2149  * Routine:   Set_Gfx_Labels                                               *
2150  *                                                                         *
2151  * Purpose:   Set the label pixmaps of the 'Rectangle', 'Polygon',         *
2152  *            'Circle', and 'Ellipse' graphics tool toggle to either       *
2153  *            Solid or Hollow, depending on the flag passed in.            *
2154  *                                                                         *
2155  *X11***********************************************************************/
2156
2157 void
2158 Set_Gfx_Labels(
2159         Boolean flag )
2160 {
2161   Arg args[10];
2162   int i;
2163
2164   if (flag == HOLLOW) {
2165     i = 0;
2166     XtSetArg(args[i], XmNlabelPixmap, rectPix); i++;
2167     XtSetValues(rectangleButton, args, i);
2168     i = 0;
2169     XtSetArg(args[i], XmNlabelPixmap, circlePix); i++;
2170     XtSetValues(circleButton, args, i);
2171     i = 0;
2172     XtSetArg(args[i], XmNlabelPixmap, polygonPix); i++;
2173     XtSetValues(polygonButton, args, i);
2174     i = 0;
2175     XtSetArg(args[i], XmNlabelPixmap, ellipsePix); i++;
2176     XtSetValues(ellipseButton, args, i);
2177    }
2178   else {
2179     i = 0;
2180     XtSetArg(args[i], XmNlabelPixmap, rectSolidPix); i++;
2181     XtSetValues(rectangleButton, args, i);
2182     i = 0;
2183     XtSetArg(args[i], XmNlabelPixmap, circleSolidPix); i++;
2184     XtSetValues(circleButton, args, i);
2185     i = 0;
2186     XtSetArg(args[i], XmNlabelPixmap, polygonSolidPix); i++;
2187     XtSetValues(polygonButton, args, i);
2188     i = 0;
2189     XtSetArg(args[i], XmNlabelPixmap, ellipseSolidPix); i++;
2190     XtSetValues(ellipseButton, args, i);
2191    }
2192 }
2193
2194
2195 /***************************************************************************
2196  *                                                                         *
2197  * Routine:   jskXerrorDebug                                               *
2198  *                                                                         *
2199  * Purpose:   This routine takes the place of the default non-fatal error  *
2200  *            handler normally used by the X server.  If an error occurs,  *
2201  *            this routine simply stores the error_code in the global      *
2202  *            variable XErrorFlag (making it available to other sections   *
2203  *            of the application).  Then it returns.                       *
2204  *                                                                         *
2205  ***************************************************************************/
2206 #define MAX_MSG_STR   1024
2207
2208 static int jskXerrorDebug(disp, error_event)
2209 Display *disp;
2210 XErrorEvent *error_event;
2211 {
2212     char error_msg[MAX_MSG_STR];
2213
2214 #ifdef DEBUG
2215     if (debug)
2216         stat_out("\n\nX Protocol Error:\n");
2217
2218     _DtPrintDefaultErrorSafe(disp, error_event, error_msg, MAX_MSG_STR);
2219     _DtSimpleError (progName, DtWarning, NULL, error_msg, NULL);
2220 #endif /* DEBUG */
2221
2222     return (TRUE);
2223 }
2224
2225
2226 /***************************************************************************
2227  *                                                                         *
2228  * Routine:   jskXerrorIODebug                                             *
2229  *                                                                         *
2230  * Purpose:   This routine is needed in order to get good bfa (bba) stats  *
2231  **************************************************************************/
2232 static int jskXerrorIODebug(disp)
2233 Display *disp;
2234 {
2235     exit (-1);
2236     return (TRUE);
2237 }
2238
2239
2240 /***************************************************************************
2241  *                                                                         *
2242  * Routine:   SaveSession                                                  *
2243  *                                                                         *
2244  * Purpose:   save state information for session management                *
2245  **************************************************************************/
2246 void
2247 SaveSession( void )
2248 {
2249     char *path, *name;
2250     int fd, n;
2251     char *xa_CommandStr[3];
2252     char *tmpStr, *tmpStr2;
2253     Position x,y;
2254     Dimension width, height;
2255     char bufr[1024];        /* make bigger if needed */
2256     XmVendorShellExtObject  vendorExt;
2257     XmWidgetExtData         extData;
2258     WM_STATE *wmState;
2259     Atom wmStateAtom, actualType;
2260     int actualFormat;
2261     unsigned long nitems, leftover;
2262
2263
2264 #ifdef DEBUG
2265   if (debug)
2266     stat_out("SaveSession\n");
2267 #endif
2268
2269     DtSessionSavePath(dtIconShell, &path, &name);
2270
2271     /*  Create the session file  */
2272     if ((fd = creat(path, S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP)) == -1)
2273     {
2274         tmpStr = GETSTR(16,24, "Couldn't save session to file");
2275         tmpStr2 = (char *)XtMalloc(strlen(tmpStr) + strlen(path)+ 3);
2276         sprintf(tmpStr2, "%s: %s\n", tmpStr, path);
2277         _DtSimpleErrnoError(progName, DtError, NULL, tmpStr2, NULL);
2278         XtFree(tmpStr2);
2279         XtFree ((char *)path);
2280         XtFree ((char *)name);
2281         return;
2282     }
2283
2284
2285     /*  Getting the WM_STATE property to see if iconified or not */
2286
2287     wmStateAtom = XInternAtom(dpy, "WM_STATE", False);
2288
2289     XGetWindowProperty (dpy, XtWindow(dtIconShell), wmStateAtom, 0L,
2290                         (long)BUFSIZ, False, wmStateAtom, &actualType,
2291                         &actualFormat, &nitems, &leftover,
2292                         (unsigned char **) &wmState);
2293
2294     if (wmState->state == IconicState)
2295         sprintf(bufr, "*iconic: True\n");
2296     else
2297         sprintf(bufr, "*iconic: False\n");
2298
2299     /*** Get and write out the geometry info for our Window ***/
2300
2301     x = XtX(dtIconShell);
2302     y = XtY(dtIconShell);
2303     width = XtWidth(dtIconShell);
2304     height = XtHeight(dtIconShell);
2305
2306     /* Modify x & y to take into account window mgr frames
2307      * This is pretty bogus, but I don't know a better way to do it.
2308      */
2309     extData = _XmGetWidgetExtData(dtIconShell, XmSHELL_EXTENSION);
2310     vendorExt = (XmVendorShellExtObject)extData->widget;
2311     x -= vendorExt->vendor.xOffset;
2312     y -= vendorExt->vendor.yOffset;
2313
2314     sprintf(bufr, "%s*x: %d\n", bufr, x);
2315     sprintf(bufr, "%s*y: %d\n", bufr, y);
2316     sprintf(bufr, "%s*width: %d\n", bufr, width);
2317     sprintf(bufr, "%s*height: %d\n", bufr, height);
2318     if (last_fname[0] != NULL)
2319         sprintf(bufr, "%s*file: %s\n", bufr, last_fname);
2320
2321     write (fd, bufr, strlen(bufr));
2322
2323
2324     n = 0;
2325     xa_CommandStr[n] = execName;    n++;
2326     xa_CommandStr[n] =  "-session"; n++;
2327     xa_CommandStr[n] = name;        n++;
2328
2329     XSetCommand(dpy, XtWindow(dtIconShell), xa_CommandStr, n);
2330     XtFree ((char *)path);
2331     XtFree ((char *)name);
2332
2333     /*  Don't exit yet, SM needs time to get the new commandStr.*/
2334 }
2335
2336
2337 /***************************************************************************
2338  *                                                                         *
2339  * Routine:   GetSessionInfo                                               *
2340  *                                                                         *
2341  * Purpose:   get dticon session information                              *
2342  **************************************************************************/
2343 #define DEFAULT_WIDTH  536
2344 #define DEFAULT_HEIGHT 477
2345
2346 void
2347 GetSessionInfo( void )
2348 {
2349     XrmDatabase db;
2350     char *tmpStr, *tmpStr2;
2351     char *path;
2352     XrmName xrm_name[5];
2353     XrmRepresentation rep_type;
2354     XrmValue value;
2355
2356 #ifdef DEBUG
2357   if (debug)
2358     stat_out("GetSessionInfo\n");
2359 #endif
2360
2361     if (xrdb.session == NULL)
2362     {
2363         session.useSession = False;
2364         return;
2365     }
2366     else
2367         session.useSession = True;
2368
2369     /***  Open the resource database file ***/
2370
2371     /* TopLevel is used because dtIconShell isn't created yet...     */
2372     /* okay because it only uses it to get a display, not a window    */
2373     if (DtSessionRestorePath(TopLevel, &path, xrdb.session) == False)
2374         path = xrdb.session;
2375
2376     if ((db = XrmGetFileDatabase (path)) == NULL)
2377     {
2378         tmpStr = GETSTR(16,22, "Couldn't restore session from file");
2379         tmpStr2 = (char *)XtMalloc(strlen(tmpStr) + strlen(path)+ 3);
2380         sprintf(tmpStr2, "%s: %s\n", tmpStr, path);
2381         _DtSimpleErrnoError(progName, DtError, NULL, tmpStr2, NULL);
2382         XtFree(tmpStr2);
2383         if (path != xrdb.session)
2384             XtFree(path);
2385         session.useSession = False;
2386         return;
2387     }
2388     if (path != xrdb.session)
2389         XtFree(path);
2390
2391
2392     /*** now get the information we want from the database ***/
2393     /*** make sure values are at least somewhat reasonable ***/
2394
2395     xrm_name[1] = NULL;
2396
2397     /* get x position */
2398     xrm_name[0] = XrmStringToQuark ("x");
2399     if (XrmQGetResource (db, xrm_name, xrm_name, &rep_type, &value))
2400         session.x = (Position)atoi((char *)value.addr);
2401     else
2402         session.x = 100;
2403     if (session.x < 0) session.x = 0;
2404
2405     /* get y position */
2406     xrm_name[0] = XrmStringToQuark ("y");
2407     if (XrmQGetResource (db, xrm_name, xrm_name, &rep_type, &value))
2408         session.y = (Position)atoi((char *)value.addr);
2409     else
2410         session.y = 100;
2411     if (session.y < 0) session.y = 0;
2412
2413     /* get width */
2414     xrm_name[0] = XrmStringToQuark ("width");
2415     if (XrmQGetResource (db, xrm_name, xrm_name, &rep_type, &value))
2416         session.width = (Dimension)atoi((char *)value.addr);
2417     else
2418         session.width = DEFAULT_WIDTH;
2419     if (session.width < DEFAULT_WIDTH) session.width = DEFAULT_WIDTH;
2420
2421     /* get height */
2422     xrm_name[0] = XrmStringToQuark ("height");
2423     if (XrmQGetResource (db, xrm_name, xrm_name, &rep_type, &value))
2424         session.height = (Dimension)atoi((char *)value.addr);
2425     else
2426         session.height = DEFAULT_HEIGHT;
2427     if (session.height < DEFAULT_HEIGHT) session.height = DEFAULT_HEIGHT;
2428
2429     /* get iconic state */
2430     xrm_name[0] = XrmStringToQuark ("iconic");
2431     if (XrmQGetResource (db, xrm_name, xrm_name, &rep_type, &value))
2432     {
2433         if ( value.addr!=NULL && strcmp((char *)value.addr, "True")==0 )
2434             session.iconicState = IconicState;
2435         else
2436             session.iconicState = NormalState;
2437     }
2438
2439     /* get file name */
2440     xrm_name[0] = XrmStringToQuark ("file");
2441     if (XrmQGetResource (db, xrm_name, xrm_name, &rep_type, &value))
2442     {
2443         strncpy(start_file, value.addr, 255);
2444     }
2445     else
2446         start_file[0] = '\0';
2447 }
2448
2449
2450 /***************************************************************************
2451  *                                                                         *
2452  * Routine:   ChangeTitle                                                  *
2453  *                                                                         *
2454  * Purpose:   Put the file name in the window title...                     *
2455  ***************************************************************************/
2456 void
2457 ChangeTitle(
2458         )
2459 {
2460     static char *dialogTitle = NULL;
2461     Arg al[10];
2462     int ac;
2463     char *name;
2464     char *title;
2465     char *tmpStr;
2466     Boolean freeName;
2467
2468     if (!dialogTitle)
2469     {
2470         name = GETSTR(12, 1, "Icon Editor");
2471         dialogTitle = XtMalloc (strlen(name) + 4);
2472         sprintf(dialogTitle, "%s - ", name);
2473     }
2474
2475     if (last_fname && *last_fname)
2476     {
2477         if (name = strrchr(last_fname, '/'))
2478             name++;
2479         else
2480             name = last_fname;
2481         freeName = False;
2482     }
2483     else
2484     {
2485         tmpStr = GETSTR(10, 66, "(UNTITLED)");
2486         name = XtNewString(tmpStr);
2487         freeName = True;
2488     }
2489
2490     title = XtMalloc (strlen(dialogTitle) + strlen(name) + 1);
2491     sprintf(title, "%s%s", dialogTitle, name);
2492
2493     ac = 0;
2494     XtSetArg(al[ac], XmNtitle, title); ac++;
2495     XtSetArg(al[ac], XmNiconName, name); ac++;
2496     XtSetValues(dtIconShell, al, ac);
2497     if(freeName == True)
2498         XtFree(name);
2499     XtFree(title);
2500 }