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