dticon: Fix some warnings related to mixing NULL, 0 and '\0' randomly.
[oweals/cde.git] / cde / programs / dticon / fileIO.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: fileIO.c /main/8 1996/10/21 17:31:11 mgreess $ */
24 /*********************************************************************
25 *  (c) Copyright 1993, 1994 Hewlett-Packard Company
26 *  (c) Copyright 1993, 1994 International Business Machines Corp.
27 *  (c) Copyright 1993, 1994, 1995 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:              fileIO.c, which contains the following subroutines or
37  **                     functions:
38  **                       Do_FileIO()
39  **                       Read_File()
40  **                       Write_File()
41  **                       Display_XPMFile()
42  **                       Display_XBMFile()
43  **                       Dump_AttribStruct()
44  **
45  ******************************************************************************
46  **
47  **  Copyright Hewlett-Packard Company, 1990, 1991, 1992.
48  **  All rights are reserved.  Copying or reproduction of this program,
49  **  except for archival purposes, is prohibited without prior written
50  **  consent of Hewlett-Packard Company.
51  **
52  **  Hewlett-Packard makes no representations about the suitibility of this
53  **  software for any purpose.  It is provided "as is" without express or
54  **  implied warranty.
55  **
56  ******************************************************************************/
57 #ifdef __osf__
58 #include <stdlib.h>   /* for getenv() function prototype */
59 #endif
60 #include <sys/param.h>
61 #include <sys/stat.h>
62 #include <Xm/Xm.h>
63 #include <Xm/TextF.h>
64 #include <Xm/FileSB.h>
65 #include <stdio.h>
66 #include <string.h>
67 #include "externals.h"
68 #include "main.h"
69
70 #ifdef __TOOLTALK
71 #include <Tt/tttk.h>
72 extern void ReplyToMessage( );
73 extern Tt_message replyMsg;
74 #endif
75
76 extern XtPointer _XmStringUngenerate (
77                                 XmString string,
78                                 XmStringTag tag,
79                                 XmTextType tag_type,
80                                 XmTextType output_type);
81
82 extern Widget   formatMenu_xpm_tb, formatMenu_xbm_tb;
83 extern Window tablet_win;
84 extern Widget editMenu_deleteHS_pb;
85 Boolean Read_File(), Write_File();
86 Pixmap pix_ret, shape_ret, mask_ret;
87 int successFormat, x_hot, y_hot;
88 unsigned int width_ret, height_ret;
89 extern GC scratch_gc;
90
91 extern void PixelTableClear();
92 extern int PixelTableLookup();
93 extern void send_tt_saved();
94 extern void Display_XPMFile(int, int);
95 extern void Display_XBMFile(int, int);
96
97
98 char  *tmpSave;            /* Save the file path being saved */
99 char  dummy[256];           /* mask file for use in main */
100 extern int SaveMeNot;
101 extern int SavedOnce;
102
103 /***************************************************************************
104  *                                                                         *
105  * Routine:   Do_FileIO                                                    *
106  *                                                                         *
107  * Purpose:   To read/write the current icon from/to the filename          *
108  *            selected in the file selection box.                          *
109  *                                                                         *
110  *            If fileIOMode is FILE_READ, this file should be read in.     *
111  *            If the read attempt fails, an error dialog pops up to        *
112  *            inform the user.                                             *
113  *                                                                         *
114  *            If fileIOMode is FILE_WRITE, the currently loaded icon       *
115  *            should be written to the named file, using the current file  *
116  *            format (specified by 'fileFormat').  As with FILE_READ, if   *
117  *            the write attempt fails, an error dialog pops up to inform   *
118  *            the user.                                                    *
119  *                                                                         *
120  ***************************************************************************/
121
122 void
123 Do_FileIO(
124         Widget wid,
125         XtPointer client_unused,
126         XmFileSelectionBoxCallbackStruct *callback_data )
127 {
128   int   unmanageFileIO = True;
129   struct stat statbuf;        /* Information on a file. */
130
131 #ifdef DEBUG
132   if (debug)
133     stat_out("Entering Do_FileIO\n");
134 #endif
135   pix_ret = 0;
136   shape_ret = 0;
137   mask_ret = 0;
138
139   /* get file name */
140   if (SaveMeNot){
141   tmpSave = (char *) _XmStringUngenerate(
142                                         callback_data->value, NULL,
143                                         XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
144   }
145
146   if (fileIOMode == FILE_READ) {
147     if (!Read_File(tmpSave))
148     {
149       unmanageFileIO = False;
150       DoErrorDialog( (GETSTR(16,2, "The file cannot be accessed\nor contains invalid data")) );
151     }
152     else {
153       if (successFormat == FORMAT_XPM) {
154         X_Hot = xpm_ReadAttribs.x_hotspot;
155         Y_Hot = xpm_ReadAttribs.y_hotspot;
156         Display_XPMFile(xpm_ReadAttribs.width, xpm_ReadAttribs.height);
157        }
158       else if (successFormat == FORMAT_XBM) {
159         X_Hot = x_hot;
160         Y_Hot = y_hot;
161         Display_XBMFile(width_ret, height_ret);
162        }
163       Dirty = False;
164       SavedOnce = True;   /* Implicitly saved, since we loaded the file */
165       /*
166          Turn off the HotSpot thing in the File menu.
167       */
168       if ( X_Hot == -1 )
169         XtSetSensitive((Widget) editMenu_deleteHS_pb, False );
170
171       if (unmanageFileIO)
172          XtUnmanageChild(fileIODialog);
173     } /* else */
174   } /* if(FileIOMode...) */
175
176   if (fileIOMode == FILE_WRITE) {
177     if (stat(tmpSave, &statbuf) == 0 && SaveMeNot)
178     {
179       DialogFlag=SAVE_AS;
180       DoQueryDialog( GETSTR(16,25, "File already exists.\n\nOK to overwrite the file?") );
181     }
182     else
183     {
184       if (!Write_File(tmpSave))
185       {
186         unmanageFileIO = False;
187         DoErrorDialog( (GETSTR(16,4, "Unable to write data to file")) );
188       }
189       else{
190           if (!SaveMeNot)
191               SaveMeNot = True;
192           Dirty = False;
193           SavedOnce = True;
194           if (unmanageFileIO)
195              XtUnmanageChild(fileIODialog);
196       }
197     }
198   }
199
200 #ifdef DEBUG
201   if (debug)
202     stat_out("Leaving Do_FileIO\n");
203 #endif
204 }
205
206
207 /***************************************************************************
208  *                                                                         *
209  * Routine:   Read_File                                                    *
210  *                                                                         *
211  * Purpose:   To read the contents of the specified file and create either *
212  *            a multi-color icon (if the file is an XPM file) or a bi-     *
213  *            color icon (if the file is an XBM file).  Further, if the    *
214  *            file is an XBM file, attempt to find a matching mask file    *
215  *            and read it as well, using to result to determine which      *
216  *            pixels should be set to transparent.                         *
217  *                                                                         *
218  ***************************************************************************/
219
220 Boolean
221 Read_File(
222         char *fnameIn )
223 {
224   char *base_name, *suffix, fname[MAXPATHLEN+1], *tmp, *tmp2;
225   unsigned int mask_width_ret, mask_height_ret;
226   int mask_x_hot, mask_y_hot, first;
227   struct stat statBuf;
228
229 #ifdef DEBUG
230   if (debug)
231     stat_out("Entering Read_File\n");
232 #endif
233
234   if ( !fnameIn || !(*fnameIn) )
235     return False;
236
237   tmp  = strchr(fnameIn, ':');
238   tmp2 = strchr(fnameIn, '/');
239
240   /*** - convert from "<host>:/..." to a path on the locale host. ***/
241   if (tmp && tmp2 && (tmp2 == tmp+1))
242   {
243     char        *netfile, *localfile;
244     
245     tmp[0] = '\0';
246     netfile = tt_host_file_netfile(fnameIn, tmp+1);
247     localfile = tt_netfile_file(netfile);
248
249     strncpy(fname, localfile, MAXPATHLEN);
250     tmp[0] = ':';
251
252     tt_free(netfile);
253     tt_free(localfile);
254   }
255   else     /* wasn't in form "<host>:/<path>" so use name as is... */
256   {
257     strcpy(fname, fnameIn);
258   }
259
260   /*** - if we got a NULL base_name, return FALSE             ***/
261   base_name = strrchr(fname, '/');
262   if (fname)
263     base_name = (base_name ? base_name + 1 : fname);
264   if (!base_name)
265     return (False);
266
267   /*** - if it's not a regular file, don't use it            ***/
268   if (stat(fname, &statBuf) == 0)                   /* success */
269   {
270     if ( (statBuf.st_mode & S_IFMT) == S_IFDIR ||
271          (statBuf.st_mode & S_IFMT) == S_IFCHR ||
272          (statBuf.st_mode & S_IFMT) == S_IFBLK )
273     {
274       return False;
275     }
276     if (statBuf.st_size == 0)
277     {
278       Process_Clear();
279       Process_Resize();
280       strcpy(last_fname, fname);
281       ChangeTitle();
282       successFormat = FORMAT_NONE;
283       return True;
284     }
285   }
286   else
287   {
288     return False;            /* file doesn't exist, return failure */
289   }
290
291
292 /*** before we do anything else, make sure ***/
293 /*** the editor interface refreshes itself ***/
294
295   XmUpdateDisplay(mainWindow);
296
297   pix_ret = 0;
298   shape_ret = 0;
299   mask_ret = 0;
300   xpm_ReadAttribs.valuemask = READ_FLAGS;
301   xpm_ReadAttribs.colorsymbols = colorSymbols;
302   xpm_ReadAttribs.numsymbols = NUM_PENS;
303
304
305 /*** if the file ends in .pm or .xpm, try reading it as an ***/
306 /*** XPM file first.  Then try XBM format if XPM fails.    ***/
307 /***                                                       ***/
308 /*** if the file ends in .bm or .xbm, try reading it as an ***/
309 /*** XBM file first.  Then try XPM format if XBM fails.    ***/
310 /***                                                       ***/
311 /*** if the file doesn't match any of these suffixes, try  ***/
312 /*** reading it as an XPM file first.  Then try XBM format ***/
313 /*** if XPM fails.                                         ***/
314
315 /*** FIRST, does a suffix exist? ***/
316   suffix = strrchr(base_name, '.');
317   if ((suffix) && ((int)strlen(suffix) > 1))
318     suffix++;
319   if (suffix) {
320     if (!strcmp(suffix, "bm") || !strcmp(suffix, "xbm"))
321       first = FORMAT_XBM;
322     else
323       first = FORMAT_XPM;
324    }
325   else
326     first = FORMAT_XPM;
327
328 /*** try to read the XPM/XBM file, in the order ***/
329 /*** specified by the 'first' format.           ***/
330   if (first == FORMAT_XPM) {
331     status = _DtXpmReadFileToPixmap(dpy, tablet_win,
332                 fname, &pix_ret, &shape_ret, &xpm_ReadAttribs);
333
334 #ifdef DEBUG
335   if (debug) {
336     if (debug_image)
337       XDestroyImage(debug_image);
338     if (debug_shape)
339       XDestroyImage(debug_shape);
340     debug_status = _DtXpmReadFileToImage(dpy, fname,
341                 &debug_image, &debug_shape, &xpm_ReadAttribs);
342    }
343 #endif
344
345     if (status != XpmSuccess) {
346       status = XReadBitmapFile(dpy, tablet_win,
347                 fname, &width_ret, &height_ret, &pix_ret, &x_hot,
348                 &y_hot);
349       if (status != BitmapSuccess) {
350 #ifdef DEBUG
351   if (debug)
352     stat_out("Leaving Read_File - XPM/XBM read attempt failed.\n");
353 #endif
354         return (False);
355        }
356       else
357         successFormat = FORMAT_XBM;
358      }
359     else
360       successFormat = FORMAT_XPM;
361    }
362   else {
363     status = XReadBitmapFile(dpy, tablet_win, fname,
364                 &width_ret, &height_ret, &pix_ret, &x_hot, &y_hot);
365     if (status != BitmapSuccess) {
366       status = _DtXpmReadFileToPixmap(dpy, tablet_win,
367                 fname, &pix_ret, &shape_ret, &xpm_ReadAttribs);
368       if (status != XpmSuccess) {
369 #ifdef DEBUG
370   if (debug)
371     stat_out("Leaving Read_File - XBM/XPM read attempt failed.\n");
372 #endif
373         return (False);
374        }
375       else
376         successFormat = FORMAT_XPM;
377      }
378     else
379       successFormat = FORMAT_XBM;
380    }
381
382 /*** If we got this far, we successfully read in a file. ***/
383 /*** If the 'successFormat' is FORMAT_XBM, try to find   ***/
384 /*** and accompanying mask file and load it too.  The    ***/
385 /*** format for a mask file name is:                     ***/
386 /***     <pathname><base_name>_m<suffix> (optional suffix)***/
387   if (successFormat == FORMAT_XBM) {
388 /*** does a suffix exist? ***/
389     if (suffix) {
390       strncpy(dummy, fname, ((suffix-fname)-1));
391       dummy[(int) (suffix-fname)-1] = '\0';
392       strcat(dummy, "_m.");
393       strcat(dummy, suffix);
394 #ifdef DEBUG
395   if (debug) {
396     stat_out("  full-filename = '%s'\n", fname);
397     stat_out("  suffix = '%s'\n", suffix);
398    }
399 #endif
400      }
401     else {
402          strcpy(dummy, fname);
403          strcat(dummy, "_m");
404     }
405 #ifdef DEBUG
406   if (debug)
407     stat_out("  mask-file = '%s'\n", dummy);
408 #endif
409     status = XReadBitmapFile(dpy, tablet_win, dummy,
410                 &mask_width_ret, &mask_height_ret, &mask_ret,
411                 &mask_x_hot, &mask_y_hot);
412     if (status == BitmapSuccess) {
413       if ((width_ret != mask_width_ret) || (height_ret != mask_height_ret)) {
414         XFreePixmap(dpy, mask_ret);
415         mask_ret = 0;
416        }
417      }
418     else
419       mask_ret = 0;
420    }
421
422   strcpy(last_fname, fname);
423   ChangeTitle();
424
425 #ifdef DEBUG
426   if (debug) {
427     stat_out("Finished Reading file '%s'\n", last_fname);
428     stat_out("Leaving Read_File\n");
429    }
430 #endif
431
432   return (True);
433 }
434
435
436 /***************************************************************************
437  *                                                                         *
438  * Routine:   Write_File                                                   *
439  *                                                                         *
440  * Purpose:   To write the current icon to the specified filename as       *
441  *            either an XPM file or XBM file, depending on the current     *
442  *            value of the fileFormat flag.  Further, if the current       *
443  *            fileFormat is FORMAT_XBM, create a second XBM file which     *
444  *            contains a mask for the XBM file just written.               *
445  *                                                                         *
446  ***************************************************************************/
447 Boolean
448 Write_File(
449         char *fnameIn )
450 {
451   extern int tt_tmpfile_fd;
452   int i, j;
453   int mask_needed;
454   Boolean SUN;
455   char *base_name, *suffix, fname[256], *tmp, *tmp2, *vend;
456   Pixmap scratch_pix;
457   XImage *scratch_shape, *scratch_mask;
458   struct stat statbuf;        /* Information on a file. */
459
460
461 #ifdef DEBUG
462   if (debug)
463     stat_out("Entering Write_File\n");
464 #endif
465   SUN = False;   /* Assume machine other than SUN */
466   if ( !fnameIn || !(*fnameIn) )
467     return False;
468
469   tmp  = strchr(fnameIn, ':');
470   tmp2 = strchr(fnameIn, '/');
471
472   /*** - convert from "<host>:/..." to a path on the locale host. ***/
473   if (tmp && tmp2 && (tmp2 == tmp+1))
474   {
475     char        *netfile, *localfile;
476     
477     tmp[0] = '\0';
478     netfile = tt_host_file_netfile(fnameIn, tmp+1);
479     localfile = tt_netfile_file(netfile);
480
481     strncpy(fname, localfile, MAXPATHLEN);
482     tmp[0] = ':';
483
484     tt_free(netfile);
485     tt_free(localfile);
486   }
487   else     /* wasn't in form "<host>:/<path>" so use name as is... */
488   {
489     strcpy(fname, fnameIn);
490   }
491
492
493   base_name = strrchr(fname, '/');
494   if (fname) {
495     base_name = (base_name ? base_name + 1 : fname);
496   }
497
498   strcpy(last_fname, fname);
499   ChangeTitle();
500
501 #ifdef DEBUG
502   if (debug)
503     stat_out("Writing file '%s'\n", last_fname);
504 #endif
505
506   if (fileFormat == FORMAT_XPM) {
507     xpm_WriteAttribs.x_hotspot = X_Hot;
508     xpm_WriteAttribs.y_hotspot = Y_Hot;
509     xpm_WriteAttribs.width  = icon_width;
510     xpm_WriteAttribs.height = icon_height;
511     xpm_WriteAttribs.cpp    = 1;
512     xpm_WriteAttribs.colorsymbols = colorSymbols;
513     xpm_WriteAttribs.numsymbols = NUM_PENS;
514     xpm_WriteAttribs.ncolors = NUM_PENS;
515     xpm_WriteAttribs.valuemask = WRITE_FLAGS;
516 #ifdef DEBUG
517   if (debug)
518     Dump_AttribStruct(&xpm_WriteAttribs);
519 #endif
520     status = _DtXpmWriteFileFromPixmap(dpy, fname, color_icon, 0,
521                                 &xpm_WriteAttribs);
522
523 /*******
524     status = _DtXpmWriteFileFromPixmap(dpy, fname, color_icon, NULL, NULL);
525 ********/
526     if (status != XpmSuccess) {
527 #ifdef DEBUG
528   if (debug) {
529     stat_out("Leaving Write_File - XPM write failed. ");
530     switch (status) {
531       case XpmOpenFailed : stat_out("(XpmOpenFailed)\n"); break;
532       case XpmNoMemory   : stat_out("(XpmNoMemory)\n"); break;
533       default            : stat_out("(UNKNOWN cause)\n"); break;
534     }
535   }
536 #endif
537       return (False);
538     }
539   }
540   else {
541 /*** FIRST, does a suffix exist? ***/
542   suffix = strrchr(base_name, '.');
543   if ((suffix) && ((int)strlen(suffix) > 1))
544     suffix++;
545 /*** SECOND, is it a valid suffix? ***/
546   if (suffix) {
547     if (strcmp(suffix, "bm") && strcmp(suffix, "xbm"))
548       suffix = NULL;
549   }
550 /*** THIRD, construct the mask filename ***/
551     if (suffix) {
552       strncpy(dummy, fname, ((suffix-fname)-1));
553       dummy[(int) (suffix-fname)-1] = '\0';
554       strcat(dummy, "_m.");
555       strcat(dummy, suffix);
556     }
557     else {
558       strcpy(dummy, fname);
559       strcat(dummy, "_m");
560     }
561 /*** FOURTH, construct XImages for the shape and mask bitmaps ***/
562     mask_needed = False;
563     scratch_shape = XGetImage(dpy, mono_icon, 0, 0, icon_width, icon_height,
564                         AllPlanes, format);
565     scratch_mask = XGetImage(dpy, mono_icon, 0, 0, icon_width, icon_height,
566                         AllPlanes, format);
567     if (!scratch_shape || !scratch_mask) {
568       if (scratch_shape)
569         XDestroyImage(scratch_shape);
570       if (scratch_mask)
571         XDestroyImage(scratch_mask);
572       return (False);
573     }
574
575     /* is this a SUN machine?                   */
576     /* if so use special code else use old code */
577     vend = ServerVendor(dpy);
578     if ( strncmp( vend, "Sun", 3) == 0) {
579        SUN = TRUE;
580        for (i=0; i<icon_width; i++)
581          for (j=0; j<icon_height; j++)
582            if (XGetPixel(scratch_shape, i, j) == Transparent) {
583             XPutPixel(scratch_shape, i, j,  white_pixel);
584             mask_needed = True;
585         }
586        for (i=0; i<icon_width; i++)
587          for (j=0; j<icon_height; j++)
588            if (XGetPixel(scratch_mask, i, j) != Transparent)
589              XPutPixel(scratch_mask, i, j,  black_pixel);
590            else
591              XPutPixel(scratch_mask, i, j,  white_pixel);
592     }else {
593        for (i=0; i<icon_width; i++)
594          for (j=0; j<icon_height; j++)
595           if (XGetPixel(scratch_shape, i, j) == Transparent) {
596             XPutPixel(scratch_shape, i, j,  black_pixel);
597             mask_needed = True;
598           }
599        for (i=0; i<icon_width; i++)
600          for (j=0; j<icon_height; j++)
601            if (XGetPixel(scratch_mask, i, j) != Transparent)
602              XPutPixel(scratch_mask, i, j,  white_pixel);
603            else
604              XPutPixel(scratch_mask, i, j,  black_pixel);
605     }
606
607
608 /*** FIFTH, write out the shape and mask bitmaps ***/
609     scratch_pix = XCreatePixmap(dpy, root, icon_width, icon_height,
610                                 DefaultDepth(dpy, screen));
611     if (!scratch_pix) {
612       if (scratch_shape)
613         XDestroyImage(scratch_shape);
614       if (scratch_mask)
615         XDestroyImage(scratch_mask);
616       return (False);
617     }
618     /* don't set GXcopyInverte for SUN machines */
619     if (!SUN)
620     XSetFunction(dpy, Mono_gc, GXcopyInverted);
621     XPutImage(dpy, scratch_pix, Mono_gc, scratch_shape, 0, 0, 0, 0,
622                         icon_width, icon_height);
623     XSetFunction(dpy, Mono_gc, GXcopy);
624     status = XWriteBitmapFile(dpy, fname, scratch_pix, icon_width, icon_height,
625                         X_Hot, Y_Hot);
626     if (status != BitmapSuccess)
627     {
628       XDestroyImage(scratch_shape);
629       XDestroyImage(scratch_mask);
630       XFreePixmap(dpy, scratch_pix);
631       return (False);
632     }
633     if (mask_needed) {
634       XPutImage(dpy, scratch_pix, Mono_gc, scratch_mask, 0, 0, 0, 0,
635                         icon_width, icon_height);
636       status = XWriteBitmapFile(dpy, dummy, scratch_pix, icon_width,
637                         icon_height, X_Hot, Y_Hot);
638       if (status != BitmapSuccess)
639       {
640         XDestroyImage(scratch_shape);
641         XDestroyImage(scratch_mask);
642         XFreePixmap(dpy, scratch_pix);
643         return (False);
644       }
645     } /***TAG***/
646     XFreePixmap(dpy, scratch_pix);
647     XDestroyImage(scratch_shape);
648     XDestroyImage(scratch_mask);
649   } /* else */
650
651   /* Don't know if this is needed....
652   if ( SUN )
653      {
654         SUN = False;
655         black_pixel = 0;
656         white_pixel = 1;
657      }
658   */
659
660 #ifdef DEBUG
661   if (debug)
662     stat_out("Leaving Write_File\n");
663 #endif
664     if( (fileFormat != FORMAT_XPM) && (!mask_needed) && (stat(tmpSave, &statbuf) == 0) )
665       unlink(dummy);
666 #ifdef __TOOLTALK
667     if (tt_tmpfile_fd != -1)
668        send_tt_saved();
669 #endif
670
671   return (True);
672 }
673
674 /***************************************************************************
675  *                                                                         *
676  * Routine:   Display_XPMFile                                              *
677  *                                                                         *
678  * Purpose:   Assuming that we have successfully read in an XPM file, use  *
679  *            the data from the file to render the proper rasters to the   *
680  *            color_icon and mono_icon (and their corresponding widgets).  *
681  *                                                                         *
682  *            Rendering the color icon is straight-forward, since the      *
683  *            pixmap generated by Read_File() is already correct.  For     *
684  *            the mono icon, we extract an XImage for the entire color     *
685  *            pixmap, and then convert each pixel individually to one      *
686  *            three values: black, white, or transparent.  For each pixel, *
687  *            the following test is performed: 1st) compare it to each     *
688  *            static color.  If a match is found, convert the pixel to     *
689  *            the appropriate mono equivalent.  2nd) if the 1st step fails *
690  *            to find a match, try the same comparisons against the        *
691  *            dynamic colors.  3rd) if the 2nd step also fails, use the    *
692  *            PixelTableLookup() function.                                 *
693  *                                                                         *
694  *            Once the coversion process is complete, both the color_icon  *
695  *            and mono_icon (and their corresponding widgets) can be       *
696  *            rendered.                                                    *
697  *                                                                         *
698  ***************************************************************************/
699
700 void
701 Display_XPMFile(
702         int width,
703         int height )
704 {
705   int converted, i, j, k;
706   int pixelTableIndex;
707   XImage *scratch_img, *mono_img, *mask_img;
708   Pixel cpixel, mpixel;
709 #ifdef DEBUG
710   int reset_debug;
711 #endif
712
713 #ifdef DEBUG
714   if (debug)
715     stat_out("Entering Display_XPMFile\n");
716   reset_debug=False;
717 #endif
718
719 /*** resize the color and mono icon windows, and the tablet ***/
720 /*** to their (new) correct height and width.               ***/
721   Init_Icons(width, height, DO_NOT_SAVE);
722
723 /*** Grab an image for both (potentially modified) ***/
724 /*** color and mono conversions                    ***/
725   scratch_img = XGetImage(dpy, pix_ret, 0, 0, width, height,
726                                 AllPlanes, format);
727   mono_img = XGetImage(dpy, pix_ret, 0, 0, width, height,
728                                 AllPlanes, format);
729   mask_img = NULL;
730   if (shape_ret)
731     mask_img = XGetImage(dpy, shape_ret, 0, 0, width, height,
732                                 AllPlanes, format);
733 #ifdef DEBUG
734   if (debug) {
735     debug = False;
736     reset_debug = True;
737    }
738 #endif
739   PixelTableClear;  /* force new pixel table now */
740   for (i=0; i<width; i++)
741     for (j=0; j<height; j++) {
742       converted = False;
743       cpixel = XGetPixel(scratch_img, i, j);
744       if (mask_img) {
745         mpixel = XGetPixel(mask_img, i, j);
746         if (!mpixel) {
747           cpixel = Transparent;
748           XPutPixel(scratch_img, i, j, cpixel);
749          }
750        } /* if(mask_img) */
751       for (k = 0; k < NUM_STATICS; k++)
752         if (cpixel == StaticPen[k]) {
753           XPutPixel(mono_img, i, j, StaticMono[k]);
754           converted = True;
755          } /* if(cpixel...) */
756       if (!converted) {
757         for (k = 0; k < NUM_DYNAMICS; k++)
758           if (cpixel == DynamicPen[k]) {
759             XPutPixel(mono_img, i, j, DynamicMono[k]);
760             converted = True;
761            } /* if(cpixel...) */
762        } /* if(!converted) */
763       if (!converted) {
764         pixelTableIndex = PixelTableLookup (cpixel, False);
765         XPutPixel(mono_img, i, j, PIXEL_TABLE_MONO(pixelTableIndex));
766        } /* if(!converted) */
767      } /* for(j...) */
768 #ifdef DEBUG
769   if (reset_debug) {
770     debug = True;
771     reset_debug = False;
772    }
773 #endif
774
775   XPutImage(dpy, color_icon, Color_gc, scratch_img,
776                 0, 0, 0, 0, width, height);
777   XPutImage(dpy, mono_icon, Mono_gc, mono_img,
778                 0, 0, 0, 0, width, height);
779
780 /*** this following stuff all gets done regardless ***/
781
782   XCopyArea(dpy, color_icon, XtWindow(iconImage),
783                 Color_gc, 0, 0, width, height, 0, 0);
784   XCopyArea(dpy, mono_icon, XtWindow(monoImage),
785                 Mono_gc, 0, 0, width, height, 0, 0);
786   icon_width = width;
787   icon_height = height;
788   fileFormat = FORMAT_XPM;
789   XmToggleButtonGadgetSetState(formatMenu_xpm_tb, True, True);
790 /* This line is not realy needed since an Exposed event will be generated */
791   Repaint_Exposed_Tablet();
792   XDestroyImage(scratch_img);
793   XFreePixmap(dpy, pix_ret);
794   if (shape_ret)
795     XFreePixmap(dpy, shape_ret);
796
797 #ifdef DEBUG
798   if (debug)
799     stat_out("Leaving Display_XPMFile\n");
800 #endif
801 }
802
803
804 /***************************************************************************
805  *                                                                         *
806  * Routine:   Display_XBMFile                                              *
807  *                                                                         *
808  * Purpose:   Assuming that we have successfully read in an X bitmap file  *
809  *            (and, potentially, a mask file as well), use the data from   *
810  *            the file(s) to render the proper rasters to the color_icon   *
811  *            and mono_icon (and their corresponding widgets).             *
812  *                                                                         *
813  *            Rendering the bitmap is straight-forward (create a scratch   *
814  *            pixmap of the correct depth and copy-plane the just-read     *
815  *            bitmap onto it).  If there is a mask bitmap as well, then    *
816  *            the scratch pixmap must be modified such that for every      *
817  *            0 bit in the mask bitmap, the corresponding pixel of the     *
818  *            scratch pixmap should be set to the Transparent pixel.       *
819  *            Once this is done, the scratch pixmap is copied to both      *
820  *            the color_icon and mono_icon (since, for bitmaps, they're    *
821  *            identical).  Then free the scratch pixmap.                   *
822  *                                                                         *
823  ***************************************************************************/
824
825 void
826 Display_XBMFile(
827         int width,
828         int height )
829 {
830   int i, j;
831   XImage *test_img, *scratch_img;
832   Pixmap scratch_pix;
833
834 #ifdef DEBUG
835   if (debug)
836     stat_out("Entering Display_XBMFile\n");
837 #endif
838
839   scratch_pix = XCreatePixmap(dpy, root, width, height,
840                                 DefaultDepth(dpy, screen));
841   Init_Icons(width, height, DO_NOT_SAVE);
842   XSetBackground(dpy, scratch_gc, white_pixel);
843   XFillRectangle(dpy, scratch_pix, scratch_gc, 0, 0, width, height);
844   XSetForeground(dpy, scratch_gc, black_pixel);
845   XCopyPlane(dpy, pix_ret, scratch_pix, scratch_gc, 0, 0,
846                 width, height, 0, 0, 1);
847   if (mask_ret) {
848     test_img = XGetImage(dpy, mask_ret, 0, 0, width, height,
849         AllPlanes, format);
850     scratch_img = XGetImage(dpy, scratch_pix, 0, 0, width, height,
851         AllPlanes, format);
852     for (i=0; i<width; i++)
853       for (j=0; j<height; j++)
854         if (!XGetPixel(test_img, i, j))
855           XPutPixel(scratch_img, i, j, Transparent);
856     XPutImage(dpy, scratch_pix, scratch_gc, scratch_img,
857                 0, 0, 0, 0, width, height);
858    } /* if(mask_ret) */
859   XCopyArea(dpy, scratch_pix, color_icon, Color_gc, 0, 0,
860                 width, height, 0, 0);
861   XCopyArea(dpy, scratch_pix, mono_icon, Mono_gc, 0, 0,
862                 width, height, 0, 0);
863   XCopyArea(dpy, color_icon, XtWindow(iconImage),
864                 Color_gc, 0, 0, width, height, 0, 0);
865   XCopyArea(dpy, mono_icon, XtWindow(monoImage),
866                 Mono_gc, 0, 0, width, height, 0, 0);
867   icon_width = width;
868   icon_height = height;
869   fileFormat = FORMAT_XBM;
870   XmToggleButtonGadgetSetState(formatMenu_xbm_tb, True, True);
871 /* This line is not realy needed since an Exposed event will be generated */
872   Repaint_Exposed_Tablet();
873   if (mask_ret) {
874     XDestroyImage(test_img);
875     XDestroyImage(scratch_img);
876    }
877   XFreePixmap(dpy, scratch_pix);
878   XFreePixmap(dpy, pix_ret);
879   if (mask_ret)
880     XFreePixmap(dpy, mask_ret);
881
882 #ifdef DEBUG
883   if (debug)
884     stat_out("Leaving Display_XBMFile\n");
885 #endif
886 }
887
888
889 /***************************************************************************
890  *                                                                         *
891  * Routine:   SetFileIODialogInfo                                          *
892  *                                                                         *
893  * Purpose:   Set FileIODialog information... title, path, etc.            *
894  *                                                                         *
895  ***************************************************************************/
896 void
897 SetFileIODialogInfo( void )
898 {
899   static int currentTitle = SAVE_AS;  /* initial title is for Save_As... */
900   static XmString saveTitle = NULL;
901   static XmString openTitle = NULL;
902   static XmString saveLabel = NULL;
903   static XmString openLabel = NULL;
904   static XmString OpenOKLabel = NULL;
905   static XmString SaveOKLabel = NULL;
906
907   static char *untitledStr = NULL;
908   static Widget textWidget = NULL;
909   static char newName[MAX_FNAME];
910   static char dirStr[MAX_FNAME];
911   static char tmpStr[MAX_FNAME];
912
913   Arg args[10];
914   int  n,dirlen=0,filelen=0,tst, ln;
915   char *strOrig = NULL;
916   XmString  tmpXmStr;
917   char tmp[MAX_FNAME];
918   char *tmp1= NULL;
919   char *tmp2= NULL;
920   int c;
921   int startSelect, endSelect;
922
923   if (DialogFlag == OPEN) /* Dialog is for File-Open menu item */
924   {
925     /* set title to "Icon Editor - Open File" if needed */
926       if (!openTitle)
927         openTitle = GETXMSTR(2,8,  "Icon Editor - Open File");
928       n = 0;
929       XtSetArg (args[n], XmNdialogTitle, openTitle);         n++;
930       XtSetValues (fileIODialog, args, n);
931       currentTitle = OPEN;
932
933       /* set selection label to "Open File" */
934       if (!openLabel)
935         openLabel = GETXMSTR(2,17,  "Enter file name:");
936       n = 0;
937       XtSetArg (args[n], XmNselectionLabelString, openLabel);         n++;
938       OpenOKLabel = GETXMSTR(2,22,  "Open");
939       XtSetArg (args[n], XmNokLabelString, OpenOKLabel);              n++;
940       XtSetValues (fileIODialog, args, n);
941   }
942   else  /* Dialog is for File-Save or File-Save_As menu item */
943   {
944     /* set title to "Icon Editor - Save As" if needed */
945       if (!saveTitle)
946         saveTitle = GETXMSTR(2,6,  "Icon Editor - Save As");
947       n = 0;
948       XtSetArg (args[n], XmNdialogTitle, saveTitle);         n++;
949       XtSetValues (fileIODialog, args, n);
950       currentTitle = SAVE_AS;
951
952       /* set selection label to "Enter file name:" */
953       if (!saveLabel)
954         saveLabel = GETXMSTR(2,16,  "Enter file name:");
955       n = 0;
956       XtSetArg (args[n], XmNselectionLabelString, saveLabel);         n++;
957       SaveOKLabel = GETXMSTR(2,24,  "Save");
958       XtSetArg (args[n], XmNokLabelString, SaveOKLabel);              n++;
959       XtSetValues (fileIODialog, args, n);
960   }
961     /*                                                  */
962     /* set string to "UNTITLED" with appropriate suffix */
963     /* when apropriate                                  */
964
965     if (!untitledStr)
966       untitledStr = GETSTR(2,20, "UNTITLED");
967     if (!textWidget)
968       textWidget = XmFileSelectionBoxGetChild(fileIODialog, XmDIALOG_TEXT);
969     strOrig = XmTextFieldGetString(textWidget);
970
971     dirStr[0] = '\0';
972     newName[0]='\0';
973     tmpStr[0]='\0';
974     startSelect = 0;
975
976     /* prepare to test */
977     tmp1 = strrchr(strOrig, '.');
978
979     strcat(tmpStr, untitledStr);
980     strcat(tmpStr, ".m.pm");
981     tst=strcmp(last_fname, tmpStr);
982
983     if ( tst==0 ) {/* untitled */
984        if ( tmp1 ) { /* previous string exists */
985           if (currentTitle != SAVE_AS) strcat(newName, strOrig);
986           else {
987                strcat(newName, untitledStr);
988                strcat(newName, ".m.pm");}
989                /* Update the FSB */
990                XmFileSelectionDoSearch(fileIODialog,(XmString)NULL);
991
992        }
993        else { /* First time arownd */
994           if (strOrig && strOrig[0]!='\0')
995              strcat(newName, strOrig);
996           else {
997              strcat(newName, untitledStr);
998              strcat(newName, ".m.pm");
999           }
1000
1001     XSync(dpy, 0);
1002           /* rebuild last file name */
1003           last_fname[0] = '\0';
1004           strcpy(last_fname, dirStr);
1005           strcat(last_fname, newName);
1006        }
1007     }
1008     else { /* not untitled */
1009          tmp1= strrchr(last_fname, '/');
1010
1011          /*
1012           * Check if any '/' characters found
1013           */
1014          if (tmp1)
1015          {
1016              /*
1017               * Strip path into directory name and file name
1018               */
1019              c = tmp1[1];
1020              tmp2 = strchr(tmp1, c);
1021              strcpy(newName, tmp2);
1022
1023              /* make and insert the directory name */
1024              ln = strlen(last_fname) - strlen(tmp1);
1025              strncpy(dirStr, last_fname, ln);
1026              dirStr[ln] = '\0';
1027          }
1028          else
1029          {
1030              /*
1031               * Path is a simple filename
1032               * Set filename to be path name
1033               * Set directory name = "."
1034               */
1035              strcpy(newName, last_fname);
1036              dirStr[0] = '.';
1037              dirStr[1] = '\0';
1038          }
1039
1040          tmpXmStr = XmStringCreateLocalized (dirStr);
1041          n = 0;
1042          XtSetArg (args[n], XmNdirectory, tmpXmStr);      n++;
1043          XtSetValues (fileIODialog, args, n);
1044          XmStringFree(tmpXmStr);
1045     }
1046      ln=0;
1047      /* set the Highlighted string */
1048      newName[strlen(newName)+1] ='\0';
1049      tmp1 = strchr(newName, '.');
1050      if (tmp1 && tmp1[0]!='\0') ln = (int)strlen(tmp1);
1051      endSelect = strlen(newName)- ln;
1052
1053     /* now set the text field and set selection for highlighted portion */
1054     XmTextFieldSetString(textWidget, newName);
1055     XmTextFieldSetSelection(textWidget, startSelect, endSelect, CurrentTime);
1056
1057     XSync(dpy, 0);
1058     XmProcessTraversal(textWidget, XmTRAVERSE_CURRENT);
1059     XSync(dpy, 0);
1060
1061     XtFree(strOrig);
1062
1063   /* if file lists are being used, re-scan the directory contents */
1064  /* if (xrdb.useFileLists)
1065     XmFileSelectionDoSearch(fileIODialog, NULL);*/
1066 }
1067
1068
1069
1070 #ifdef DEBUG
1071 /***************************************************************************
1072  *                                                                         *
1073  * Routine:   Dump_AttribStruct  #ifdef DEBUG only (for bba)               *
1074  *                                                                         *
1075  * Purpose:   Print out the entier contents of the XpmAttributes struct.   *
1076  *                                                                         *
1077  ***************************************************************************/
1078 int
1079 Dump_AttribStruct(
1080         XpmAttributes *xpma )
1081 {
1082   int i, j;
1083
1084   if (xpma->valuemask) {
1085     stat_out("  valuemask: (");
1086     if (xpma->valuemask & XpmVisual)
1087         stat_out("XpmVisual|");
1088     if (xpma->valuemask & XpmColormap)
1089         stat_out("XpmColormap|");
1090     if (xpma->valuemask & XpmDepth)
1091         stat_out("XpmDepth|");
1092     if (xpma->valuemask & XpmSize)
1093         stat_out("XpmSize|");
1094     if (xpma->valuemask & XpmHotspot)
1095         stat_out("XpmHotspot|");
1096     if (xpma->valuemask & XpmCharsPerPixel)
1097         stat_out("XpmCharsPerPixel|");
1098     if (xpma->valuemask & XpmColorSymbols)
1099         stat_out("XpmColorSymbols|");
1100     if (xpma->valuemask & XpmRgbFilename)
1101         stat_out("XpmRgbFilename|");
1102     if (xpma->valuemask & XpmInfos)
1103         stat_out("XpmInfos");
1104     stat_out(")\n");
1105    }
1106   else
1107     stat_out("  valuemask: NULL\n");
1108
1109   stat_out("  Colormap: %d\n", xpma->colormap);
1110   stat_out("  depth: %d\n", xpma->depth);
1111   stat_out("  width: %d\n", xpma->width);
1112   stat_out("  height: %d\n", xpma->height);
1113   stat_out("  x_hotspot: %d\n", xpma->x_hotspot);
1114   stat_out("  y_hotspot: %d\n", xpma->y_hotspot);
1115   stat_out("  cpp: %d\n", xpma->cpp);
1116   stat_out("  npixels: %d\n", xpma->npixels);
1117   if (xpma->npixels) {
1118     stat_out("  Pixels: ");
1119     for (i=0; i<xpma->npixels; i++) {
1120       stat_out("%d, ", xpma->pixels[i]);
1121       if (i%10 == 0)
1122         stat_out("\n");
1123      }
1124     stat_out("\n");
1125    }
1126   stat_out("  numsymbols: %d\n", xpma->numsymbols);
1127   if (xpma->numsymbols) {
1128     for (i=0; i<xpma->numsymbols; i++)
1129       stat_out("    %18s | %18s | %d\n", xpma->colorsymbols[i].name,
1130                  xpma->colorsymbols[i].value, xpma->colorsymbols[i].pixel);
1131    }
1132   stat_out("  rgb_fname: \"%s\"\n",((xpma->rgb_fname)?(xpma->rgb_fname):"(nil)"));
1133   stat_out("  ---------------------------------\n");
1134   stat_out("  ncolors: %d\n", xpma->ncolors);
1135   if (xpma->ncolors) {
1136     for (i=0; i<xpma->ncolors; i++)
1137       if (xpma->colorTable[i][0] != NULL)
1138         stat_out("    %3d \"%1s\" \"%18s\" \"%5s\" \"%5s\" \"%5s\" \"%5s\"\n",
1139                 i+1,
1140                 ((xpma->colorTable[i][0])?(xpma->colorTable[i][0]):"(nil)"), 
1141                 ((xpma->colorTable[i][1])?(xpma->colorTable[i][1]):"(nil)"),
1142                 ((xpma->colorTable[i][2])?(xpma->colorTable[i][2]):"(nil)"), 
1143                 ((xpma->colorTable[i][3])?(xpma->colorTable[i][3]):"(nil)"),
1144                 ((xpma->colorTable[i][4])?(xpma->colorTable[i][4]):"(nil)"), 
1145                 ((xpma->colorTable[i][5])?(xpma->colorTable[i][5]):"(nil)")
1146         );
1147    }
1148   stat_out("  hints_cmt: \"%s\"\n",((xpma->hints_cmt)?(xpma->hints_cmt):"(nil)"));
1149   stat_out("  colors_cmt: \"%s\"\n",((xpma->colors_cmt)?(xpma->colors_cmt):"(nil)"));
1150   stat_out("  pixels_cmt: \"%s\"\n",((xpma->pixels_cmt)?(xpma->pixels_cmt):"(nil)"));
1151   stat_out("  mask_pixel: 0x%x\n",xpma->mask_pixel);
1152 }
1153 #endif