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