chiark / gitweb /
Create readable text `.bas' for each tokenized BASIC `,ffb' file.
[ssr] / StraySrc / Glass / !Glass / c / tfile
1 /*
2  * tfile.c
3  *
4  * Control of template files
5  *
6  * © 1994-1998 Straylight
7  */
8
9 /*----- Licensing note ----------------------------------------------------*
10  *
11  * This file is part of Straylight's Glass.
12  *
13  * Glass is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2, or (at your option)
16  * any later version.
17  *
18  * Glass is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with Glass.  If not, write to the Free Software Foundation,
25  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 /*
31  * ANSI standard headers
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 /*
39  * Steel headers
40  */
41
42 #define _STDAPP
43 #define _XFER
44 #define _LOWLVL
45 #include "steel/Steel.h"
46
47 #include "steel/viewer.h"
48 #include "steel/mem.h"
49 #include "steel/nopoll.h"
50 #include "steel/flex.h"
51 #include "steel/akbd.h"
52 #include "steel/alarm.h"
53 #include "steel/bbc.h"
54 #include "steel/buffer.h"
55 #include "steel/font.h"
56
57 /*
58  * Glass headers
59  */
60
61 #include "gStruct.h"
62 #include "gIcons.h"
63 #include "gMenus.h"
64
65 #include "glass.h"
66 #include "toolbox.h"
67 #include "intMsgs.h"
68 #include "tfile.h"
69 #include "gPrefs.h"
70 #include "gSprite.h"
71 #include "indir.h"
72 #include "window.h"
73 #include "editWin.h"
74 #include "iconData.h"
75
76 /*----- Constants ---------------------------------------------------------*/
77
78 #define tfile__FILEHEIGHT 892    /* Height to open first template window   */
79 #define tfile__FILEX 200         /* x position of template file windows    */
80 #define tfile__FILETOP 940       /* Height after files wrap around         */
81
82 #define tfile__WINDHEIGHT 872    /* Height to create first window          */
83 #define tfile__WINDX 450         /* x position of template windows         */
84 #define tfile__WINDTOP 920       /* Height after windows wrap around       */
85
86 /*----- Static global variables -------------------------------------------*/
87
88 static int tfile__unsavedFiles;   /* Number of files not saved             */
89 static int tfile__fileHeight=tfile__FILEHEIGHT;
90                                  /* Height to open next template window    */
91 static int tfile__windHeight=tfile__WINDHEIGHT;
92 static int tfile__selectSize;    /* Size in bytes of current selection     */
93 static int tfile__selectIcons;   /* Number of icons in current selection   */
94 static int tfile__selectIndSz;   /* Indirected data size for selection     */
95 static char tfile__grabName[15]; /* Name for the grabbed window            */static glass_tfile *tfile__selOwner;   /* Owner of the current selection   */
96
97 /*----- Support routines --------------------------------------------------*/
98
99 /*
100  * void tfile__tidyFonts(viewer_icon i,void *handle)
101  *
102  * Use
103  *  Closes down the fonts on a particular template file.
104  *
105  * Parameters
106  *  viewer_icon i == the icon (ignored)
107  *  void *handle == the file to close
108  */
109
110 static void tfile__tidyFonts(viewer_icon ic,void *handle)
111 {
112   int i,j;
113   glass_windPointer *w=handle;
114   unused(ic);
115   if (w->antiAliased)
116   {
117     for (i=0;i<256;i++)
118     {
119       for (j=0;j<w->fonts[i];j++)
120         wimpt_noerr(font_lose(i));
121     }
122   }
123   w->antiAliased=FALSE;
124 }
125
126 /*
127  * void tfile__reFindFonts(viewer_icon ic,void *handle)
128  *
129  * Use
130  *  Scans the given window, refinding all the fonts it used.  This is
131  *  because (at present) on a mode change, the aspect ratio can become
132  *  utterly trashed.  I can't afford to wait until the Font Manager gets
133  *  rewritten to work properly, so I have to do it myself...
134  *
135  *  After this call, the window needs recreating if it's being displayed.
136  *  It will pick up the Open_Window_Request, and recreate on that if it
137  *  finds it has some fonts in it.
138  *
139  *  This call also resets the antiAliased flag if it finds no fonts in a
140  *  window.
141  *
142  * Parameters
143  *  viewer_icon ic == the viewer icon of the window to rescan (ignored)
144  *  void *handle == an undercover glass_windPointer * to the window
145  */
146
147 static void tfile__reFindFonts(viewer_icon ic,void *handle)
148 {
149   glass_windPointer *w=handle;
150   int i;
151   int icf;
152   os_regset r;
153   int fhand;
154   int newhand;
155   BOOL usedAFont=FALSE;
156   char buff[50];
157   unused(ic);
158
159   if (!w->antiAliased)
160     return;
161   icf=w->def->desc.w.titleflags;
162   if (icf & wimp_IFONT)
163   {
164     usedAFont=TRUE;
165     fhand=(icf>>24) & 0xff;
166     r.r[0]=fhand;
167     r.r[1]=(int)buff;
168     wimpt_noerr(os_swix(XFont_ReadDefn,&r));
169     r.r[4]=r.r[5]=0;
170     if (!wimpt_complain(os_swix(XFont_FindFont,&r)))
171     {
172       newhand=r.r[0];
173       r.r[0]=fhand;
174       wimpt_noerr(os_swix(XFont_LoseFont,&r));
175       w->fonts[fhand]--;
176       w->fonts[newhand]++;
177       w->def->desc.w.titleflags=(icf & 0x00ffffff) | (newhand<<24);
178     }
179   }
180   for (i=0;i<w->def->desc.w.nicons;i++)
181   {
182     icf=w->def->i[i].i.flags;
183     if (icf & wimp_IFONT)
184     {
185       usedAFont=TRUE;
186       fhand=(icf>>24) & 0xff;
187       r.r[0]=fhand;
188       r.r[1]=(int)buff;
189       wimpt_noerr(os_swix(XFont_ReadDefn,&r));
190       r.r[4]=r.r[5]=0;
191       if (!wimpt_complain(os_swix(XFont_FindFont,&r)))
192       {
193         newhand=r.r[0];
194         r.r[0]=fhand;
195         wimpt_noerr(os_swix(XFont_LoseFont,&r));
196         w->fonts[fhand]--;
197         w->fonts[newhand]++;
198         w->def->i[i].i.flags=(icf & 0x00ffffff) | (newhand<<24);
199       }
200     }
201   }
202   w->antiAliased=usedAFont;
203 }
204
205 /*
206  * void tfile__gainSelection(glass_tfile *t)
207  *
208  * Use
209  *  Hands the current tfile selection and the input focus to the specified
210  *  template file.
211  *
212  *  Note that the selection model here is more complex than it is in window,
213  *  since the focus tfile may not coincide with the selection owner (since
214  *  menu clicks move the selection owner, but not the focus).
215  *
216  * Parameters
217  *  glass_tfile *t == the template to which we give the focus
218  */
219
220 static void tfile__gainSelection(glass_tfile *t)
221 {
222   wimp_caretstr c;
223   if (t!=tfile__selOwner)
224   {
225     if (tfile__selOwner)
226       viewer_selectAll(tfile__selOwner->v,FALSE);
227     tfile__selOwner=t;
228   }
229   if (t)
230   {
231     c.w=viewer_syshandle(t->v);
232     c.i=-1;
233     c.x=-250;
234     c.y=0;
235     c.index=-1;
236     c.height=0x02000000;
237     wimpt_noerr(wimp_set_caret_pos(&c));
238   }
239 }
240
241 /*
242  * void tfile__doDeleteWindow(void *handle)
243  *
244  * Use
245  *  Deletes, trashes and exterminates a window.
246  *
247  * Parameters
248  *  void *handle ==  the window to eliminate
249  */
250
251 static void tfile__doDeleteWindow(void *handle)
252 {
253   int i;
254   glass_windPointer *w=handle;
255   window_hasBeenDeleted(w);
256   if (w->def->desc.w.titleflags & wimp_INDIRECT)
257   {
258     indir_free(w->def->desc.w.title.indirecttext.buffer);
259     if ((w->def->desc.w.titleflags & wimp_ITEXT) &&
260         (w->def->desc.w.title.indirecttext.validstring!=(char *)-1))
261       indir_free(w->def->desc.w.title.indirecttext.validstring);
262   }
263   for (i=0;i<w->def->desc.w.nicons;i++)
264   {
265     if (w->def->i[i].i.flags & wimp_INDIRECT)
266     {
267       indir_free(w->def->i[i].i.data.indirecttext.buffer);
268       if ((w->def->i[i].i.flags & wimp_ITEXT) &&
269           (w->def->i[i].i.data.indirecttext.validstring!=(char *)-1))
270         indir_free(w->def->i[i].i.data.indirecttext.validstring);
271     }
272   }
273   if (w->def)
274     flex_free((flex_ptr)&w->def);
275   if (w->h)
276   {
277     win_register_event_handler(w->h,0,0);
278     win_activedec();
279     wimpt_noerr(wimp_delete_wind(w->h));
280   }
281   tfile__tidyFonts(0,w);
282   mem_free(w);
283 }
284
285 /*
286  * void tfile__deleteTemplateFile(void *handle)
287  *
288  * Use
289  *  Trashes the named template file.
290  *
291  * Parameters
292  *  void *handle == the template file to murder
293  */
294
295 static void tfile__deleteTemplateFile(void *handle)
296 {
297   glass_tfile *t=handle;
298   intMsgs_send(glass_DELETEFILE,t);
299   if (t==tfile__selOwner)
300     tfile__selOwner=0;
301   gSprite_kill(t);
302   if (t->alts)
303     tfile__unsavedFiles--;
304   viewer_delete(t->v,tfile__doDeleteWindow);
305   if (t->autod)
306     dbox_delete(t->autod);
307   if (t->autoAlarm)
308     alarm_remove(t->autoAlarm,t);
309   mem_free(t);
310   flex_compact();
311 }
312
313 /*
314  * glass_windPointer *tfile__newWindow(glass_tfile *t,char *name)
315  *
316  * Use
317  *  Creates a new window entry in the template file specified.  It is up to
318  *  the caller to write the window definition.
319  *
320  * Parameters
321  *  glass_tfile *t == the template file to add the window to
322  *  char *name == the name of the window
323  *
324  * Returns
325  *  A pointer to the window structure
326  */
327
328 static glass_windPointer *tfile__newWindow(glass_tfile *t,char *name)
329 {
330   glass_windPointer *w;
331   int i;
332   static int serial;             /* Serial number - monotonic increasing   */
333   mem_useUser(indir_alloc,indir_free);
334   w=mem_alloc(sizeof(glass_windPointer));
335   if (!w)
336   {
337     werr(FALSE,msgs_lookup("tfNEMCRT"));
338     mem_useMalloc();
339     return (0);
340   }
341   strcpy(w->id,name);
342   w->def=0;
343   w->t=t;
344   w->h=0;
345   w->edit=0;
346   w->size=0;
347   w->gridx=gPrefs_current()->gWidth;
348   w->gridy=gPrefs_current()->gHeight;
349   w->gridShow=gPrefs_current()->gDisp;
350   w->gridLock=gPrefs_current()->gLock;
351   w->serial=serial++;                  /* Increment serial number count    */
352   for (i=0;i<glass_GUIDELIMIT;i++)
353     w->guide[i].active=FALSE;
354   w->antiAliased=FALSE;
355   for (i=0;i<256;i++)
356     w->fonts[i]=0;
357   if (w->i=viewer_addIcon(t->v,name,"tmpltvicon",TRUE,w),!w->i)
358   {
359     mem_free(w);
360     mem_useMalloc();
361     return (0);
362   }
363   viewer_setFiletype(w->i,0xfec);
364   mem_useMalloc();
365   return (w);
366 }
367
368 /*
369  * void tfile__size(viewer_icon i,void *handle)
370  *
371  * Use
372  *  Adds the size of the window given by handle to the global variables
373  *  tfile__selectSize and tfile__selectIndSz.
374  *
375  * Parameters
376  *  viewer_icon i == the viewer icon handle (ignored)
377  *  void *handle == the window to count
378  */
379
380 static void tfile__size(viewer_icon i,void *handle)
381 {
382   glass_windPointer *w=handle;
383   unused(i);
384   tfile__selectSize+=w->size;
385   tfile__selectIndSz+=w->size-
386                       sizeof(glass_window)-
387                       (w->def->desc.w.nicons-1)*
388                          sizeof(glass_iconDescription);
389 }
390
391 /*
392  * void tfile__icons(viewer_icon i,void *handle)
393  *
394  * Use
395  *  Adds the number of icons in  the window given by handle to the global
396  *  variable tfile__selectIcons.
397  *
398  * Parameters
399  *  viewer_icon i == the viewer icon handle (ignored)
400  *  void *handle == the window to count
401  */
402
403 static void tfile__icons(viewer_icon i,void *handle)
404 {
405   glass_windPointer *w=handle;
406   unused(i);
407   tfile__selectIcons+=w->def->desc.w.nicons;
408 }
409
410 /*
411  * BOOL tfile__create(char *new,void *handle)
412  *
413  * Use
414  *  Creates a new window.
415  *
416  * Parameters
417  *  char *new == the name for the new window
418  *  void *handle == pointer to the tfile
419  */
420
421 static BOOL tfile__create(char *new,void *handle)
422 {
423   glass_tfile *t=handle;
424   viewer_icon icn;
425   glass_windPointer *wnew;
426   wimp_wind *w=&template_find("default")->window;
427
428   icn=viewer_findIcon(t->v,new);
429   if (icn==viewer_NOICON)
430   {
431     wnew=tfile__newWindow(t,new);
432     if (!wnew)
433       return (FALSE);
434     tfile_markAsAltered(t);
435     wnew->size=sizeof(glass_window)-sizeof(glass_iconDescription);
436     if (!flex_alloc((flex_ptr)&wnew->def,wnew->size))
437     {
438       viewer_removeIcon(wnew->i);
439       mem_free(wnew);
440       werr(FALSE,msgs_lookup("tfNEMCRT"));
441       return (FALSE);
442     }
443     wnew->def->desc.w=*w;
444     wnew->def->desc.w.nicons=0;
445     if (!iconData_handleFont(wnew,&wnew->def->desc.w.titleflags))
446       werr(FALSE,msgs_lookup("tfFERC"));
447     if (wnew->def->desc.w.titleflags & wimp_IFONT)
448     {
449       wnew->antiAliased=TRUE;
450       wnew->fonts[(wnew->def->desc.w.titleflags>>24) & 0xff]++;
451     }
452     if (!iconData_processIcon(wnew,-1,0,TRUE,0))
453     {
454       werr(FALSE,msgs_lookup("tfNEMCRT"));
455       tfile_deleteWindow(0,wnew);
456       return (FALSE);
457     }
458     wnew->def->desc.w.box.y1=tfile__windHeight;
459     wnew->def->desc.w.box.y0=tfile__windHeight +
460                              wnew->def->desc.w.ex.y0 -
461                              wnew->def->desc.w.ex.y1;
462     wnew->def->desc.w.box.x0=tfile__WINDX;
463     wnew->def->desc.w.box.x1=tfile__WINDX -
464                              wnew->def->desc.w.ex.x0 +
465                              wnew->def->desc.w.ex.x1;
466     if (wnew->def->desc.w.box.y0<tfile__windHeight-500)
467       wnew->def->desc.w.box.y0=tfile__windHeight-500;
468     if (wnew->def->desc.w.box.x1>tfile__WINDX+700)
469       wnew->def->desc.w.box.x1=tfile__WINDX+700;
470     wnew->def->desc.w.scx=wnew->def->desc.w.ex.x0;
471     wnew->def->desc.w.scy=wnew->def->desc.w.ex.y1;
472     tfile__windHeight-=48;
473     if (tfile__windHeight<632)
474       tfile__windHeight=tfile__WINDTOP;
475
476     return (TRUE);
477   }
478   note(msgs_lookup("tfNAE"),viewer_textOfIcon(icn));
479   return (FALSE);
480 }
481
482 /*
483  * char *tfile__grabData(char *ptr,void *handle)
484  *
485  * Use
486  *  Grabs data from the destination task, as required when setting up a
487  *  grabbed window.
488  *
489  * Parameters
490  *  char *ptr == pointer to data string (in other task's workspace)
491  *  void *handle == not a pointer at all, actually the source task's handle
492  *
493  * Returns
494  *  A pointer to a string in my own workspace (static char array)
495  */
496
497 static char *tfile__grabData(char *ptr,void *handle)
498 {
499   char *buff=buffer_find();
500   wimp_t t=(int)handle;
501   if (t)
502   {
503     if (wimp_transferblock(t,ptr,wimpt_task(),buff,256))
504       return ("<error>");
505   }
506   else
507     return ("<indirected>");
508   return (buff);
509 }
510
511 /*
512  * void tfile__grab(wimp_mousestr *m,void *handle)
513  *
514  * Use
515  *  Grabs a window definition, inserting it neatly into the template file.
516  *
517  * Parameters
518  *  wimp_mousestr *m == info about the window
519  *  void *handle == pointer to destination template file
520  */
521
522 static void tfile__grab(wimp_mousestr *m,void *handle)
523 {
524   glass_tfile *t=handle;
525   glass_windPointer *wnew;
526   wimp_winfo *w;
527   os_regset r;
528   int numicons;
529   wimp_t task;
530   wimp_msgstr msg;
531   int i;
532   int ioff;
533   BOOL fonterr=FALSE;
534
535   wnew=tfile__newWindow(t,tfile__grabName);
536   if (!wnew)
537     return;
538   tfile_markAsAltered(t);
539   if (wimpt_getVersion()>=300)   /* RISC OS 3 allows 'safe' GetWindowInfos */
540     w=mem_alloc(sizeof(wimp_winfo));
541   else
542     w=mem_alloc(sizeof(wimp_winfo)+200*sizeof(wimp_icon));
543   if (!w)
544   {
545     werr(FALSE,msgs_lookup("tfNEMGW"));
546     viewer_removeIcon(wnew->i);
547     mem_free(wnew);
548     return;
549   }
550   w->w=m->w;
551   r.r[1]=(int)w;
552   if (wimpt_getVersion()>=300)
553     r.r[1]++;                    /* RO3 - only window header, not icons    */
554   wimpt_noerr(os_swix(XWimp_GetWindowInfo,&r)); /* Get the information     */
555   numicons=w->info.nicons;
556   mem_free(w);
557   wnew->size=sizeof(glass_window)+
558              (numicons-1)*sizeof(glass_iconDescription);
559   if (!flex_alloc((flex_ptr)&w,
560                   sizeof(wimp_winfo)+numicons*sizeof(wimp_icon)))
561   {
562     viewer_removeIcon(wnew->i);
563     mem_free(wnew);
564     werr(FALSE,msgs_lookup("tfNEMGW"));
565     return;
566   }
567   if (!flex_alloc((flex_ptr)&wnew->def,wnew->size))
568   {
569     flex_free((flex_ptr)&w);
570     viewer_removeIcon(wnew->i);
571     mem_free(wnew);
572     werr(FALSE,msgs_lookup("tfNEMGW"));
573     return;
574   }
575   w->w=m->w;
576   r.r[1]=(int)w;
577   wimpt_noerr(os_swix(XWimp_GetWindowInfo,&r)); /* Read the window properly*/
578
579   msg.hdr.size=20;
580   msg.hdr.your_ref=0;
581   msg.hdr.action=0;
582   r.r[0]=19;
583   r.r[1]=(int)&msg;
584   r.r[2]=m->w;
585   r.r[3]=m->i;
586   if (os_swix(XWimp_SendMessage,&r))
587     task=0;
588   else
589     task=r.r[2];
590
591   wnew->def->desc.w=w->info;
592   wnew->def->desc.w.nicons=0;
593   if (!iconData_handleFont(wnew,&wnew->def->desc.w.titleflags) && !fonterr)
594   {
595     werr(FALSE,msgs_lookup("tfFERG"));
596     fonterr=TRUE;
597   }
598   if (!iconData_processIcon(wnew,-1,tfile__grabData,TRUE,(void *)task))
599   {
600     flex_free((flex_ptr)&w);
601     tfile_deleteWindow(0,wnew);
602     werr(FALSE,msgs_lookup("tfNEMGW"));
603     return;
604   }
605
606   ioff=sizeof(wimp_winfo);
607   for (i=0;i<numicons;i++)
608   {
609     wnew->def->i[i].i=*_ptr(wimp_icon,w,ioff);
610     wnew->def->i[i].edit=0;
611     if (!iconData_handleFont(wnew,&wnew->def->i[i].i.flags) && !fonterr)
612     {
613       werr(FALSE,msgs_lookup("tfFERG"));
614       fonterr=TRUE;
615     }
616     if (!iconData_processIcon(wnew,i,tfile__grabData,TRUE,(void *)task))
617     {
618       flex_free((flex_ptr)&w);
619       tfile_deleteWindow(0,wnew);
620       werr(FALSE,msgs_lookup("tfNEMGW"));
621       return;
622     }
623     wnew->def->desc.w.nicons++;
624     ioff+=sizeof(wimp_icon);
625   }
626   flex_free((flex_ptr)&w);
627 }
628
629 /*
630  * BOOL tfile__grabGetName(char *name,void *handle)
631  *
632  * Use
633  *  Handles the writable box for a grab window job and starts the grab op
634  *
635  * Parameters
636  *  char *name == the user's name for the window
637  *  void *handle == the template file to grab to
638  *
639  * Returns
640  *  TRUE if the name was valid and the grab has been set up
641  */
642
643 static BOOL tfile__grabGetName(char *name,void *handle)
644 {
645   glass_tfile *t=handle;
646   viewer_icon icn;
647
648   icn=viewer_findIcon(t->v,name);
649   if (icn==viewer_NOICON)
650   {
651     strcpy(tfile__grabName,name);
652     event_clear_current_menu();
653     window_grab(tfile__grab,t);
654     return (TRUE);
655   }
656   note(msgs_lookup("tfNAE"),
657        viewer_textOfIcon(icn));
658   return (FALSE);
659 }
660
661 /*
662  * BOOL tfile__copy(char *new,void *handle)
663  *
664  * Use
665  *  Copies the specified window
666  *
667  * Parameters
668  *  char *new == the name for the new window
669  *  void *handle == pointer to the window structure
670  */
671
672 static BOOL tfile__copy(char *new,void *handle)
673 {
674   glass_windPointer *w=handle;
675   viewer_icon icn;
676   glass_windPointer *wnew;
677   int i;
678   int numicons;
679   BOOL fonterr=FALSE;
680
681   icn=viewer_findIcon(w->t->v,new);
682   if (icn==viewer_NOICON)
683   {
684     wnew=tfile__newWindow(w->t,new);
685     if (!wnew)
686       return (FALSE);
687     tfile_markAsAltered(w->t);
688     wnew->size=w->size;
689     numicons=w->def->desc.w.nicons;
690     if (!flex_alloc((flex_ptr)&wnew->def,
691                     sizeof(glass_window)
692                       +(numicons-1)*sizeof(glass_iconDescription)))
693     {
694       viewer_removeIcon(wnew->i);
695       mem_free(wnew);
696       werr(FALSE,msgs_lookup("tfNEMCW"));
697       return (FALSE);
698     }
699     memcpy
700     (
701       wnew->def,
702       w->def,
703       sizeof(glass_window)+(numicons-1)*sizeof(glass_iconDescription)
704     );
705     wnew->def->desc.w.nicons=0;
706     if (!iconData_handleFont(wnew,&wnew->def->desc.w.titleflags) && !fonterr)
707     {
708       werr(FALSE,msgs_lookup("tfFERCP"));
709       fonterr=TRUE;
710     }
711     if (!iconData_processIcon(wnew,-1,0,FALSE,0))
712     {
713       werr(FALSE,msgs_lookup("tfNEMCW"));
714       tfile_deleteWindow(0,wnew);
715       return (FALSE);
716     }
717     for (i=0;i<numicons;i++)
718     {
719       if (!iconData_handleFont(wnew,&wnew->def->i[i].i.flags) && !fonterr)
720       {
721         werr(FALSE,msgs_lookup("tfFERCP"));
722         fonterr=TRUE;
723       }
724       if (!iconData_processIcon(wnew,i,0,FALSE,0))
725       {
726         werr(FALSE,msgs_lookup("tfNEMCW"));
727         tfile_deleteWindow(0,wnew);
728         return (FALSE);
729       }
730       wnew->def->desc.w.nicons++;
731     }
732     return (TRUE);
733   }
734   note(msgs_lookup("tfNAE"),
735        viewer_textOfIcon(icn));
736   return (FALSE);
737 }
738
739 /*
740  * void tfile__openWindows(viewer_icon i,void *handle)
741  *
742  * Use
743  *  Opens a window.  This is called when the user drags icons to the icon
744  *  bar and expects them to be displayed.
745  *
746  * Parameters
747  *  viewer_icon i == the icon handle of the icon representing the window
748  *   (ignored)
749  *  void *handle == pointer to the window's static information
750  */
751
752 static void tfile__openWindows(viewer_icon i,void *handle)
753 {
754   glass_windPointer *w=handle;
755   unused(i);
756   window_open(w,FALSE);
757 }
758
759 /*----- Variables used during the save process ----------------------------*/
760
761 #ifndef glass_DEMO
762
763 static void **tfile__flex;       /* A flex block for saving data           */
764 static int tfile__flexSize;      /* Size of the flex block                 */
765 static int tfile__flexUsed;      /* How much of the block has been used    */
766 static BOOL tfile__abortSave;    /* If TRUE, abort the save process        */
767 static int tfile__nextIndex;     /* Offset to next free index entry        */
768 static char tfile__fontbinding[256]; /* Conversion realh -> internh        */
769 static char tfile__backbinding[256]; /* Reverse font binding               */
770 static char tfile__nextFont;     /* The next free internal font handle     */
771
772 /*----- Save templates support routines -----------------------------------*/
773
774 /*
775  * This section contains the actual code to save a template file or
776  * selection.
777  */
778
779 /*
780  * BOOL tfile__saveAlloc(int size)
781  *
782  * Use
783  *  Ensures that a certain quantity of space is present in the save flex
784  *  block.
785  *
786  * Parameters
787  *  int size == the size required in bytes
788  *
789  * Returns
790  *  TRUE if successful, or FALSE if allocation failed.  An error is also
791  *  reported.
792  */
793
794 static BOOL tfile__saveAlloc(int size)
795 {
796   int szreqd;
797   if (tfile__flexSize-tfile__flexUsed>size)
798     return (TRUE);
799   szreqd=(tfile__flexUsed+size+8191) & ~8191;
800   if (!flex_extend(tfile__flex,szreqd))
801   {
802     werr(FALSE,msgs_lookup("tfNEMST"));
803     return (FALSE);
804   }
805   tfile__flexSize=szreqd;
806   return (TRUE);
807 }
808
809 /*
810  * BOOL tfile__addBlock(void *p,size_t sz)
811  *
812  * Use
813  *  Adds a block of data to the end of the save block.
814  *
815  * Parameters
816  *  void *p == pointer to the block
817  *  size_t sz == the size of the block
818  *
819  * Returns
820  *  TRUE if successful
821  */
822
823 static BOOL tfile__addBlock(void *p,size_t sz)
824 {
825   if (!tfile__saveAlloc(sz))
826     return (FALSE);
827   memcpy(_ptr(void,*tfile__flex,tfile__flexUsed),p,sz);
828   tfile__flexUsed+=sz;
829   return (TRUE);
830 }
831
832 #define tfile__writeString(s,off) \
833   { \
834     strcpy(charptr(*tfile__flex,off),s); \
835     charptr(*tfile__flex,off)[strlen(s)]=13; \
836   }
837
838 /*
839  * BOOL tfile__addString(char *s)
840  *
841  * Use
842  *  Adds a ctrl-terminated string to the end of the save block.
843  *
844  * Parameters
845  *  char *s == pointer to the string to store
846  *
847  * Returns
848  *  TRUE if successful
849  */
850
851 static BOOL tfile__addString(char *s)
852 {
853   int len;
854   utils_ctermToNterm(s);
855   len=strlen(s);
856   if (!tfile__saveAlloc(len+1))
857     return (FALSE);
858   tfile__writeString(s,tfile__flexUsed);
859   tfile__flexUsed+=len+1;
860   return (TRUE);
861 }
862
863 /*
864  * void tfile__processWindow(viewer_icon icn,void *handle)
865  *
866  * Use
867  *  Saves the window given onto the end of the flex block being used for
868  *  such a purpose.  A save may be aborted by setting the variable
869  *  tfile__abortSave.
870  *
871  * Parameters
872  *  viewer_icon icn == the icon representing the window to be saved (ignored)
873  *  void *handle == pointer to the window structure in memory
874  */
875
876 static void tfile__processWindow(viewer_icon icn,void *handle)
877 {
878   int start;
879   int i;
880   int idef;
881   int ifont,rfont;
882   glass_windPointer *w=handle;
883   unused(icn);
884   if (tfile__abortSave)
885     return;
886   while (tfile__flexUsed & 3)
887     *charptr(*tfile__flex,tfile__flexUsed++)=0;
888
889   /* --- Start on the index --- */
890   intptr(*tfile__flex,tfile__nextIndex)[0]=start=tfile__flexUsed;
891   intptr(*tfile__flex,tfile__nextIndex)[2]=1;
892   tfile__writeString(w->id,tfile__nextIndex+12);
893
894   /* --- Now copy the window and icons --- */
895   if (!tfile__addBlock(&w->def->desc.w,sizeof(wimp_wind)))
896   {
897     tfile__abortSave=TRUE;
898     return;
899   }
900   for (i=0;i<w->def->desc.w.nicons;i++)
901   {
902     if (!tfile__addBlock(&w->def->i[i].i,sizeof(wimp_icon)))
903     {
904       tfile__abortSave=TRUE;
905       return;
906     }
907   }
908
909   /* --- Process window def for indirection and fonts --- */
910   _ptr(wimp_wind,*tfile__flex,start)->spritearea=(void *)1;
911   if (w->def->desc.w.titleflags & wimp_IFONT)
912   {
913     rfont=w->def->desc.w.titleflags >> 24;
914     if (tfile__fontbinding[rfont])
915       ifont=tfile__fontbinding[rfont];
916     else
917     {
918       ifont=tfile__fontbinding[rfont]=tfile__nextFont++;
919       tfile__backbinding[ifont]=rfont;
920     }
921     _ptr(wimp_wind,*tfile__flex,start) -> titleflags=
922               (w->def->desc.w.titleflags & 0x00ffffff) | (ifont << 24);
923   }
924   if (w->def->desc.w.titleflags & wimp_INDIRECT)
925   {
926     _ptr(wimp_wind,*tfile__flex,start) -> title.indirecttext.buffer=
927                                             (char *)(tfile__flexUsed-start);
928     if (!tfile__addString(w->def->desc.w.title.indirecttext.buffer))
929     {
930       tfile__abortSave=TRUE;
931       return;
932     }
933     if (w->def->desc.w.titleflags & wimp_ITEXT)
934     {
935       if (w->def->desc.w.title.indirecttext.validstring!=(char *)-1)
936       {
937         _ptr(wimp_wind,*tfile__flex,start)->title.indirecttext.validstring=
938                                              (char *)(tfile__flexUsed-start);
939         if (!tfile__addString(w->def->desc.w.title.indirecttext.validstring))
940         {
941           tfile__abortSave=TRUE;
942           return;
943         }
944       }
945     }
946     else if (w->def->desc.w.titleflags & wimp_ISPRITE)
947     {
948       _ptr(wimp_wind,*tfile__flex,start)->title.indirectsprite.spritearea=
949                                                                    (void *)1;
950     }
951   }
952
953   /* --- Now the same for the icons --- */
954   idef=start+sizeof(wimp_wind);
955   for (i=0;i<w->def->desc.w.nicons;i++)
956   {
957     if (w->def->i[i].i.flags & wimp_IFONT)
958     {
959       rfont=w->def->i[i].i.flags >> 24;
960       if (tfile__fontbinding[rfont])
961         ifont=tfile__fontbinding[rfont];
962       else
963       {
964         ifont=tfile__fontbinding[rfont]=tfile__nextFont++;
965         tfile__backbinding[ifont]=rfont;
966       }
967       _ptr(wimp_icon,*tfile__flex,idef)->flags=
968                (w->def->i[i].i.flags & 0x00ffffff) | (ifont << 24);
969     }
970     if (w->def->i[i].i.flags & wimp_INDIRECT)
971     {
972       _ptr(wimp_icon,*tfile__flex,idef)->data.indirecttext.buffer=
973                                              (char *)(tfile__flexUsed-start);
974       if (!tfile__addString(w->def->i[i].i.data.indirecttext.buffer))
975       {
976         tfile__abortSave=TRUE;
977         return;
978       }
979       if (w->def->i[i].i.flags & wimp_ITEXT)
980       {
981         if (w->def->i[i].i.data.indirecttext.validstring!=(char *)-1)
982         {
983           _ptr(wimp_icon,*tfile__flex,idef)->data.indirecttext.validstring=
984                                              (char *)(tfile__flexUsed-start);
985           if (!tfile__addString(w->def->i[i].i.data.
986                                 indirecttext.validstring))
987           {
988             tfile__abortSave=TRUE;
989             return;
990           }
991         }
992       }
993       else if (w->def->i[i].i.flags & wimp_ISPRITE)
994       {
995         _ptr(wimp_icon,*tfile__flex,idef)->data.indirectsprite.spritearea=
996                                                                    (void *)1;
997       }
998     }
999     idef+=sizeof(wimp_icon);
1000   }
1001   intptr(*tfile__flex,tfile__nextIndex)[1]=tfile__flexUsed-start;
1002   tfile__nextIndex+=24;
1003 }
1004
1005 /*
1006  * BOOL tfile__setupSave(glass_tfile *t,
1007  *                       glass_windPointer *w,
1008  *                       void **p,
1009  *                       BOOL onlySelected)
1010  *
1011  * Use
1012  *  Sets up a flex block for saving a template file, selection or single
1013  *  window.  To save a template file or selection, set t==tfile, w==0.  To
1014  *  save a window, set t==0, w==window.
1015  *
1016  * Parameters
1017  *  glass_tfile *t == the template file that we're saving
1018  *  glass_windPointer *w == the window we're saving
1019  *  void **p == pointer used as flex anchor (free after use yourself)
1020  *  BOOL onlySelected == do we only save the selected templates?
1021  *
1022  * Returns
1023  *  TRUE if operation completed successfully
1024  */
1025
1026 static BOOL tfile__setupSave(glass_tfile *t,
1027                              glass_windPointer *w,
1028                              void **p,
1029                              BOOL onlySelected)
1030 {
1031   int i;
1032   int numwin;
1033   os_regset r;
1034   char buff[40];
1035   if (!flex_alloc(p,tfile__selectSize))
1036   {
1037     werr(FALSE,msgs_lookup("tfNEMST"));
1038     return (FALSE);
1039   }
1040   tfile__flex=p;
1041   tfile__flexSize=tfile__selectSize;
1042   tfile__flexUsed=0;
1043   tfile__abortSave=FALSE;
1044   for (i=0;i<256;i++)
1045   {
1046     tfile__fontbinding[i]=0;
1047     tfile__backbinding[i]=0;
1048   }
1049   tfile__nextFont=1;
1050
1051   /* --- Header --- */
1052   if (!tfile__saveAlloc(16))
1053   {
1054     flex_free(p);
1055     return (FALSE);
1056   }
1057   intptr(*tfile__flex,0)[0]=-1;
1058   intptr(*tfile__flex,0)[1]=0;
1059   intptr(*tfile__flex,0)[2]=0;
1060   intptr(*tfile__flex,0)[3]=0;
1061   tfile__flexUsed+=16;
1062
1063   /* --- Set up index entries --- */
1064   if (t)
1065   {
1066     if (onlySelected)
1067       numwin=viewer_selected(t->v);
1068     else
1069       numwin=viewer_icons(t->v);
1070   }
1071   else
1072     numwin=1;
1073   if (!tfile__saveAlloc(24*numwin+4))
1074   {
1075     flex_free(p);
1076     return (FALSE);
1077   }
1078
1079   /* --- Now insert window and icon definitions --- */
1080   tfile__nextIndex=16;
1081   tfile__flexUsed+=24*numwin+4;
1082   if (t)
1083     viewer_doForIcons(t->v,onlySelected,tfile__processWindow);
1084   else
1085     tfile__processWindow(0,w);
1086   if (tfile__abortSave)
1087   {
1088     flex_free(p);
1089     return (FALSE);
1090   }
1091
1092   /* --- Terminate the index and fill in the fonts --- */
1093   intptr(*tfile__flex,tfile__nextIndex)[0]=0;
1094   if (tfile__nextFont!=1)
1095   {
1096     tfile__flexUsed=(tfile__flexUsed+3) & (~3);
1097     if (!tfile__saveAlloc(48*(tfile__nextFont-1)))
1098     {
1099       flex_free(p);
1100       return (FALSE);
1101     }
1102     intptr(*tfile__flex,0)[0]=tfile__flexUsed;
1103     for (i=1;i<tfile__nextFont;i++)
1104     {
1105       r.r[0]=tfile__backbinding[i];
1106       r.r[1]=(int)buff;
1107       wimpt_noerr(os_swix(XFont_ReadDefn,&r));
1108       intptr(*tfile__flex,tfile__flexUsed)[0]=r.r[2];
1109       intptr(*tfile__flex,tfile__flexUsed)[1]=r.r[3];
1110       tfile__writeString(buff,tfile__flexUsed+8);
1111       tfile__flexUsed+=48;
1112     }
1113   }
1114   return (TRUE);
1115 }
1116
1117 /*
1118  * BOOL tfile__saveTemplates(char *filename,void *handle)
1119  *
1120  * Use
1121  *  Saves a template file to disk
1122  *
1123  * Parameters
1124  *  char *filename == the file to save to
1125  *  void *handle == pointer to the template file
1126  *
1127  * Returns
1128  *  TRUE if successful
1129  */
1130
1131 static BOOL tfile__saveTemplates(char *filename,void *handle)
1132 {
1133   void *p;
1134   os_filestr f;
1135   glass_tfile *t=handle;
1136   if
1137   (
1138     gPrefs_current()->cSave &&
1139     saveas_file_is_safe() &&
1140     utils_caselessCmp(filename,t->filename)!=0 &&
1141     res_fileExists(filename)
1142   )
1143   {
1144     if (!warning(msgs_lookup("tfSOFP"),msgs_lookup("tfSOF"),filename))
1145       return (FALSE);
1146   }
1147   if (!tfile__setupSave(t,0,&p,FALSE))
1148     return (FALSE);
1149   f.action=10;
1150   f.name=filename;
1151   f.loadaddr=0xfec;
1152   f.start=(int)p;
1153   f.end=f.start+tfile__flexUsed;
1154   if (utils_complain(os_file(&f),msgs_lookup("tfERT")))
1155   {
1156     flex_free(&p);
1157     return (FALSE);
1158   }
1159   else
1160   {
1161     flex_free(&p);
1162     if (saveas_file_is_safe())
1163       tfile_markAsSaved(t,filename);
1164     return (TRUE);
1165   }
1166 }
1167
1168 /*
1169  * BOOL tfile__sendTemplates(void *handle,int *maxbuf)
1170  *
1171  * Use
1172  *  Saves a template file to another application via RAM transfer
1173  *
1174  * Parameters
1175  *  void *handle == pointer to the template file
1176  *  int *maxbuf == pointer to receiving app's buffer size
1177  *
1178  * Returns
1179  *  TRUE if successful
1180  */
1181
1182 static BOOL tfile__sendTemplates(void *handle,int *maxbuf)
1183 {
1184   void *p;
1185   glass_tfile *t=handle;
1186   if (!tfile__setupSave(t,0,&p,FALSE))
1187     return (FALSE);
1188   if (xfersend_sendBlock(p,tfile__flexUsed,maxbuf))
1189   {
1190     flex_free(&p);
1191     return (TRUE);
1192   }
1193   else
1194   {
1195     flex_free(&p);
1196     return (FALSE);
1197   }
1198 }
1199
1200 /*
1201  * BOOL tfile__saveSelection(char *filename,void *handle)
1202  *
1203  * Use
1204  *  Saves a template selection to disk
1205  *
1206  * Parameters
1207  *  char *filename == the file to save to
1208  *  void *handle == pointer to the template file
1209  *
1210  * Returns
1211  *  TRUE if successful
1212  */
1213
1214 static BOOL tfile__saveSelection(char *filename,void *handle)
1215 {
1216   void *p;
1217   os_filestr f;
1218   glass_tfile *t=handle;
1219   if
1220   (
1221     gPrefs_current()->cSave &&
1222     saveas_file_is_safe() &&
1223     res_fileExists(filename)
1224   )
1225   {
1226     if (!warning(msgs_lookup("tfSOFP"),msgs_lookup("tfSOF"),filename))
1227       return (FALSE);
1228   }
1229   if (!tfile__setupSave(t,0,&p,TRUE))
1230     return (FALSE);
1231   f.action=10;
1232   f.name=filename;
1233   f.loadaddr=0xfec;
1234   f.start=(int)p;
1235   f.end=f.start+tfile__flexUsed;
1236   if (utils_complain(os_file(&f),msgs_lookup("tfERT")))
1237   {
1238     flex_free(&p);
1239     return (FALSE);
1240   }
1241   else
1242   {
1243     flex_free(&p);
1244     return (TRUE);
1245   }
1246 }
1247
1248 /*
1249  * BOOL tfile__sendSelection(void *handle,int *maxbuf)
1250  *
1251  * Use
1252  *  Saves a template selection to another application via RAM transfer
1253  *
1254  * Parameters
1255  *  void *handle == pointer to the template file
1256  *  int *maxbuf == pointer to receiving app's buffer size
1257  *
1258  * Returns
1259  *  TRUE if successful
1260  */
1261
1262 static BOOL tfile__sendSelection(void *handle,int *maxbuf)
1263 {
1264   void *p;
1265   glass_tfile *t=handle;
1266   if (!tfile__setupSave(t,0,&p,TRUE))
1267     return (FALSE);
1268   if (xfersend_sendBlock(p,tfile__flexUsed,maxbuf))
1269   {
1270     flex_free(&p);
1271     return (TRUE);
1272   }
1273   else
1274   {
1275     flex_free(&p);
1276     return (FALSE);
1277   }
1278 }
1279
1280 /*
1281  * BOOL tfile__saveWindow(char *filename,void *handle)
1282  *
1283  * Use
1284  *  Saves a template selection to disk
1285  *
1286  * Parameters
1287  *  char *filename == the file to save to
1288  *  void *handle == pointer to the window
1289  *
1290  * Returns
1291  *  TRUE if successful
1292  */
1293
1294 static BOOL tfile__saveWindow(char *filename,void *handle)
1295 {
1296   void *p;
1297   os_filestr f;
1298   glass_windPointer *w=handle;
1299   if
1300   (
1301     gPrefs_current()->cSave &&
1302     saveas_file_is_safe() &&
1303     res_fileExists(filename)
1304   )
1305   {
1306     if (!warning(msgs_lookup("tfSOFP"),msgs_lookup("tfSOF"),filename))
1307       return (FALSE);
1308   }
1309   if (!tfile__setupSave(0,w,&p,TRUE))
1310     return (FALSE);
1311   f.action=10;
1312   f.name=filename;
1313   f.loadaddr=0xfec;
1314   f.start=(int)p;
1315   f.end=f.start+tfile__flexUsed;
1316   if (utils_complain(os_file(&f),msgs_lookup("tfERT")))
1317   {
1318     flex_free(&p);
1319     return (FALSE);
1320   }
1321   else
1322   {
1323     flex_free(&p);
1324     return (TRUE);
1325   }
1326 }
1327
1328 /*
1329  * BOOL tfile__sendWindow(void *handle,int *maxbuf)
1330  *
1331  * Use
1332  *  Saves a template selection to another application via RAM transfer
1333  *
1334  * Parameters
1335  *  void *handle == pointer to the window
1336  *  int *maxbuf == pointer to receiving app's buffer size
1337  *
1338  * Returns
1339  *  TRUE if successful
1340  */
1341
1342 static BOOL tfile__sendWindow(void *handle,int *maxbuf)
1343 {
1344   void *p;
1345   glass_windPointer *w=handle;
1346   if (!tfile__setupSave(0,w,&p,TRUE))
1347     return (FALSE);
1348   if (xfersend_sendBlock(p,tfile__flexUsed,maxbuf))
1349   {
1350     flex_free(&p);
1351     return (TRUE);
1352   }
1353   else
1354   {
1355     flex_free(&p);
1356     return (FALSE);
1357   }
1358 }
1359
1360 #else
1361
1362 static BOOL tfile__demoSave(void)
1363 {
1364   note(msgs_lookup("tfCSID"));
1365 }
1366
1367 static BOOL tfile__saveTemplates(char *filename,void *handle)
1368 {
1369   unused(filename);
1370   unused(handle);
1371   return (tfile__demoSave());
1372 }
1373
1374 static BOOL tfile__sendTemplates(void *handle,int *maxbuf)
1375 {
1376   unused(handle);
1377   unused(maxbuf);
1378   return (tfile__demoSave());
1379 }
1380
1381 static BOOL tfile__saveSelection(char *filename,void *handle)
1382 {
1383   unused(filename);
1384   unused(handle);
1385   return (tfile__demoSave());
1386 }
1387
1388 static BOOL tfile__sendSelection(void *handle,int *maxbuf)
1389 {
1390   unused(handle);
1391   unused(maxbuf);
1392   return (tfile__demoSave());
1393 }
1394
1395 static BOOL tfile__saveWindow(char *filename,void *handle)
1396 {
1397   unused(filename);
1398   unused(handle);
1399   return (tfile__demoSave());
1400 }
1401
1402 static BOOL tfile__sendWindow(void *handle,int *maxbuf)
1403 {
1404   unused(handle);
1405   unused(maxbuf);
1406   return (tfile__demoSave());
1407 }
1408
1409 #endif
1410
1411 /*----- Autosave handling -------------------------------------------------*
1412  *
1413  * This is here to avoid having to prototype the save code
1414  */
1415
1416 /*
1417  * void tfile__closeQbox(int now,void *handle)
1418  *
1419  * Use
1420  *  Closes the autosave message dialogue box.
1421  *
1422  * Parameters
1423  *  int now == the time now (ignored)
1424  *  void *handle == dialogue box handle
1425  */
1426
1427 static void tfile__closeQbox(int now,void *handle)
1428 {
1429   unused(now);
1430   dbox_delete((dbox)handle);
1431 }
1432
1433 /*
1434  * void tfile__autoHandler(dbox d,dbox_field f,void *handle)
1435  *
1436  * Use
1437  *  Handles events for the autosave prompt box
1438  *
1439  * Parameters
1440  *  dbox d == the dbox's handle
1441  *  dbox_field f == what happened
1442  *  void *handle == pointer to the template file
1443  */
1444
1445 static void tfile__autoHandler(dbox d,dbox_field f,void *handle)
1446 {
1447   glass_tfile *t=handle;
1448   wimp_wstate s;
1449   switch (f)
1450   {
1451     case glass_APSAVE:
1452       if (strchr(t->filename,'.'))
1453       {
1454         dbox_clickicon(d,f);
1455         wimpt_noerr(wimp_get_wind_state(dbox_syshandle(d),&s));
1456         dbox_hide(d);
1457         if (!tfile__saveTemplates(t->filename,t))
1458           wimpt_noerr(wimp_open_wind(&s.o));
1459         dbox_unclick();
1460         break;
1461       }
1462       /* If no path, drop through to saveas... */
1463     case glass_APSAVEAS:
1464       dbox_clickicon(d,glass_APSAVEAS);
1465       dbox_unclick();
1466       tfile_saveTemplates(t);
1467       break;
1468     case glass_APCANCEL:
1469       dbox_clickicon(d,f);
1470       dbox_hide(d);
1471       dbox_unclick();
1472       /* Intentional drop through */
1473     case dbox_CLOSE:
1474       dbox_delete(d);
1475       t->autod=0;
1476       break;
1477   }
1478 }
1479
1480 /*
1481  * void tfile__doAutosave(glass_tfile *t)
1482  *
1483  * Use
1484  *  Starts an autosave for the given template file.  Multiple autosaves
1485  *  are permitted simultaneously.  Stick that in Impression's pipeline and
1486  *  process it...
1487  *
1488  * Parameters
1489  *  glass_tfile *t == the template file to autosave
1490  */
1491
1492 static void tfile__doAutosave(int now,void *handle)
1493 {
1494   BOOL useDbox;
1495   dbox qwin;
1496   int at;
1497   glass_tfile *t=handle;
1498   unused(now);
1499   useDbox=gPrefs_current()->aPrompt;
1500   if (t->loaded==FALSE || t->autoSaved==FALSE)
1501     useDbox=TRUE;
1502   if (t->autoAlarm)
1503     alarm_remove(t->autoAlarm,t);
1504   t->autoAlarm=0;
1505   t->autoTime=0;
1506   t->alts=-1;
1507   if (useDbox)
1508   {
1509     if (t->autod)
1510       return;
1511     t->autod=dbox_create("autoPrompt");
1512     if (!t->autod)
1513     {
1514       if (at=gPrefs_autoTiming(),at)
1515       {
1516         t->autoTime=alarm_timenow();
1517         t->autoAlarm=t->autoTime+at;
1518         alarm_set(t->autoAlarm,tfile__doAutosave,t);
1519       }
1520       return;
1521     }
1522     dbox_setfield(t->autod,glass_APNAME,"%.%s",t->filename);
1523     dbox_shadeicon(t->autod,glass_APSAVE,!strchr(t->filename,'.'));
1524     dbox_eventHandler(t->autod,tfile__autoHandler,t);
1525     dbox_openDisplaced(t->autod);
1526   }
1527   else
1528   {
1529     qwin=dbox_create("autoMessage");
1530     if (qwin)
1531     {
1532       dbox_setfield(qwin,glass_AMNAME,"%.%s",t->filename);
1533       dbox_display(qwin,dbox_MENU_CENTRE);
1534       nopoll_showDbox(qwin,nopoll_CENTRE);
1535       alarm_set(alarm_timenow()+100,tfile__closeQbox,qwin);
1536     }
1537     tfile__saveTemplates(t->filename,t);
1538   }
1539 }
1540
1541 /*----- Event handlers ----------------------------------------------------*/
1542
1543 /*
1544  * void tfile__close(glass_tfile *t,BOOL checkMouse)
1545  *
1546  * Use
1547  *  Closes a template file, asking user for confirmation etc.
1548  *
1549  * Parameters
1550  *  glass_tfile *t == the template file to kill
1551  *  BOOL checkMouse == whether to check the mouse buttons to open the parent
1552  */
1553
1554 static void tfile__close(glass_tfile *t,BOOL checkMouse)
1555 {
1556   wimp_mousestr m;
1557   char buff[256];
1558   char *name;
1559   event_clear_current_menu(); /* The menu will be closed - it will try */
1560                              /* to deselect an non-existant item...    */
1561   if (checkMouse)
1562   {
1563     wimpt_noerr(wimp_get_point_info(&m));
1564     if (m.bbits==wimp_BRIGHT && t->loaded)
1565     {
1566       sprintf(buff,"Filer_OpenDir %s",t->filename);
1567       utils_leafname(buff)[-1]=0;
1568       os_cli(buff);
1569     }
1570     if (m.bbits==wimp_BRIGHT && akbd_pollsh())
1571       return;
1572   }
1573   if (t->alts && gPrefs_current()->cClose)
1574   {
1575     if (t->loaded)
1576       name=t->filename;
1577     else
1578       name=msgs_lookup("tfTMP");
1579     tfile__selectSize=0;
1580     viewer_doForIcons(t->v,FALSE,tfile__size);
1581     viewer_clickSelect(t->v,viewer_NOICON,wimp_BMID);
1582     saveWarn(t->loaded,
1583              tfile__deleteTemplateFile,
1584              msgs_lookup("tfSVTIT"),
1585              name,0xfec,
1586              tfile__selectSize,
1587              tfile__saveTemplates,
1588              tfile__sendTemplates,
1589              0,
1590              t);
1591   }
1592   else
1593     tfile__deleteTemplateFile(t); /* Destroy the underlying data       */
1594 }
1595
1596 /*
1597  * void tfile__redrawViewer(viewer_icon i,wimp_redrawstr *r,
1598  *          wimp_box *box,char *text,char *sprite,BOOL selected,void *handle)
1599  *
1600  * Use
1601  *  Redraws a small icon in the viewer window.
1602  *
1603  * Parameters
1604  *  viewer_icon i == the icon I'm redrawing
1605  *  wimp_redrawstr *r == the redraw structure
1606  *  wimp_box *box == the box to fit it in
1607  *  char *text == the text to draw
1608  *  char *sprite == the sprite to draw (ignored)
1609  *  BOOL selected == whether the icon is selected
1610  *  void *handle == pointer to the template file
1611  */
1612
1613 static void tfile__redrawViewer(viewer_icon i,
1614                                 wimp_redrawstr *r,
1615                                 wimp_box *box,
1616                                 char *text,
1617                                 char *sprite,
1618                                 BOOL selected,
1619                                 void *handle)
1620 {
1621   wimp_icon icn={0,0,0,0,0x17000113,""};
1622   unused(i);
1623   unused(r);
1624   unused(sprite);
1625   unused(handle);
1626   icn.box=*box;
1627   icn.flags|=(selected<<21);
1628   icn.data.indirecttext.buffer=text;
1629   icn.data.indirecttext.validstring="Ssmtmpltvicon";
1630   icn.data.indirecttext.bufflen=13;
1631   wimpt_noerr(wimp_ploticon(&icn));
1632 }
1633
1634 /*
1635  * int tfile__sort(void *a,void *b)
1636  *
1637  * Use
1638  *  Compares two windows in the current sorting method.
1639  *
1640  * Parameters
1641  *  void *a == pointer to the first window
1642  *  void *b == pointer to the second window
1643  *
1644  * Returns
1645  *  Somehow 'a-b'.
1646  */
1647
1648 static int tfile__sort(void *a,void *b)
1649 {
1650   glass_windPointer *x=a;
1651   glass_windPointer *y=b;
1652   int result=0;
1653   switch (x->t->sort)
1654   {
1655     case gPrefs_NAME:
1656       result=utils_caselessCmp(x->id,y->id);
1657       break;
1658     case gPrefs_SIZE:
1659       result=y->size-x->size;
1660       break;
1661     case gPrefs_ICONS:
1662       result=y->def->desc.w.nicons-x->def->desc.w.nicons;
1663       break;
1664     case gPrefs_NOSORT:
1665       result=x->serial-y->serial;
1666       break;
1667   }
1668   if (!result)
1669     result=utils_caselessCmp(x->id,y->id);
1670   return (result);
1671 }
1672
1673 /*
1674  * void tfile__tfileMenuHelp(int hit[],void *handle)
1675  *
1676  * Use
1677  *  Responds to help requests for template file menu.
1678  *
1679  * Parameters
1680  *  int hit[] == array of menu selections
1681  *  void *handle == pointer to template file control block
1682  */
1683
1684 static void tfile__tfileMenuHelp(int hit[],void *handle)
1685 {
1686   unused(handle);
1687   help_startHelp();
1688   help_readFromMenu("tfmhTF",hit);
1689   help_endHelp();
1690 }
1691
1692 /*
1693  * void tfile__tfileMenuHandler(int hit[],void *handle)
1694  *
1695  * Use
1696  *  Responds to menu events for template file menu.
1697  *
1698  * Parameters
1699  *  int hit[] == array of menu selections
1700  *  void *handle == pointer to template file control block
1701  */
1702
1703 static void tfile__tfileMenuHandler(int hit[],void *handle)
1704 {
1705   glass_tfile *t=handle;
1706   char buff[15];
1707   dbox d;
1708   unused(t);
1709   switch (hit[0])
1710   {
1711     case 0:
1712       viewer_clickSelect(t->v,viewer_NOICON,wimp_BMID);
1713       break;
1714     case glass_TFINFO:
1715       if (d=dbox_create("fileInfo"),d)
1716       {
1717         dbox_setfield(d,glass_FINAME,"%.%s",t->filename);
1718         tfile__selectSize=0;
1719         tfile__selectIndSz=0;
1720         viewer_doForIcons(t->v,FALSE,tfile__size);
1721         dbox_setfield(d,
1722                       glass_FISIZE,
1723                       "%s",
1724                       utils_cvtSize(tfile__selectSize));
1725         dbox_setfield(d,
1726                       glass_FIINDSZ,
1727                       "%s",
1728                       utils_cvtSize(tfile__selectIndSz));
1729         dbox_setfield(d,glass_FIWINDOWS,"%i",viewer_icons(t->v));
1730         dbox_setfield(d,
1731                       glass_FIMODIFIED,
1732                       "%s",
1733                       msgs_lookup(t->alts ? "yes" : "no"));
1734         mbox(d,"tfhFI");
1735       }
1736       break;
1737     case glass_TFDISP:
1738       switch (hit[1])
1739       {
1740         case glass_TFDLARGE:
1741           if (t->isz!=gPrefs_LARGE)
1742           {
1743             t->isz=gPrefs_LARGE;
1744             viewer_setIconSize(t->v,200,112);
1745             viewer_redrawHandler(t->v,0,t);
1746           }
1747           break;
1748         case glass_TFDSMALL:
1749           if (t->isz!=gPrefs_SMALL)
1750           {
1751             t->isz=gPrefs_SMALL;
1752             viewer_setIconSize(t->v,248,36);
1753             viewer_redrawHandler(t->v,tfile__redrawViewer,t);
1754           }
1755           break;
1756         case glass_TFDSORTNAME:
1757           if (t->sort!=gPrefs_NAME)
1758           {
1759             t->sort=gPrefs_NAME;
1760             viewer_setCompare(t->v,tfile__sort);
1761           }
1762           break;
1763         case glass_TFDSORTSIZE:
1764           if (t->sort!=gPrefs_SIZE)
1765           {
1766             t->sort=gPrefs_SIZE;
1767             viewer_setCompare(t->v,tfile__sort);
1768           }
1769           break;
1770         case glass_TFDSORTICONS:
1771           if (t->sort!=gPrefs_ICONS)
1772           {
1773             t->sort=gPrefs_ICONS;
1774             viewer_setCompare(t->v,tfile__sort);
1775           }
1776           break;
1777         case glass_TFDNOSORT:
1778           if (t->sort!=gPrefs_NOSORT)
1779           {
1780             t->sort=gPrefs_NOSORT;
1781             viewer_setCompare(t->v,tfile__sort);
1782           }
1783           break;
1784       }
1785       break;
1786     case glass_TFSEL:
1787       switch (hit[1])
1788       {
1789         case glass_TFSELINFO:
1790           if (viewer_selected(t->v)==1)
1791             tfile_windowInfo((glass_windPointer *)
1792                               viewer_iconHandle(viewer_firstSelected(t->v)));
1793           else
1794           {
1795             if (d=dbox_create("selInfo"),d)
1796             {
1797               tfile__selectSize=0;
1798               tfile__selectIndSz=0;
1799               viewer_doForIcons(t->v,TRUE,tfile__size);
1800               dbox_setfield(d,
1801                             glass_SISIZE,
1802                             "%s",
1803                             utils_cvtSize(tfile__selectSize));
1804               dbox_setfield(d,
1805                             glass_SIINDSZ,
1806                             "%s",
1807                             utils_cvtSize(tfile__selectIndSz));
1808               tfile__selectIcons=0;
1809               viewer_doForIcons(t->v,TRUE,tfile__icons);
1810               dbox_setfield(d,glass_SIICONS,"%i",tfile__selectIcons);
1811               dbox_setfield(d,glass_SINUM,"%i",viewer_selected(t->v));
1812               mbox(d,"tfhSI");
1813             }
1814           }
1815           break;
1816         case glass_TFSELEDIT:
1817           editWindow(viewer_iconHandle(viewer_firstSelected(t->v)));
1818           break;
1819         case glass_TFSELCOPY:
1820           writable
1821           (
1822             msgs_lookup("tfCOPY"),
1823             viewer_textOfIcon(viewer_firstSelected(t->v)),
1824             buff,
1825             tfile__copy,
1826             viewer_iconHandle(viewer_firstSelected(t->v))
1827           );
1828           break;
1829         case glass_TFSELRENAME:
1830           writable
1831           (
1832             msgs_lookup("tfREN"),
1833             viewer_textOfIcon(viewer_firstSelected(t->v)),
1834             buff,
1835             tfile_rename,
1836             viewer_iconHandle(viewer_firstSelected(t->v))
1837           );
1838           break;
1839         case glass_TFSELSAVE:
1840           tfile__selectSize=0;
1841           viewer_doForIcons(t->v,TRUE,tfile__size);
1842           saveas(msgs_lookup("tfSVSEL"),
1843                  msgs_lookup("tfSEL"),
1844                  0xfec,
1845                  tfile__selectSize,
1846                  tfile__saveSelection,
1847                  tfile__sendSelection,
1848                  0,
1849                  t);
1850           break;
1851         case glass_TFSELDELETE:
1852           if (gPrefs_current()->cDelWind)
1853           {
1854             if (!warning(msgs_lookup("tfDELWP"),msgs_lookup("tfDELW")))
1855               break;
1856           }
1857           viewer_doForIcons(t->v,TRUE,tfile_deleteWindow);
1858           tfile_markAsAltered(t);
1859           break;
1860       }
1861       break;
1862     case glass_TFSELALL:
1863       tfile__gainSelection(t);
1864       viewer_selectAll(t->v,TRUE);
1865       break;
1866     case glass_TFCLRSEL:
1867       viewer_selectAll(t->v,FALSE);
1868       break;
1869     case glass_TFSAVE:
1870       tfile_saveTemplates(t);
1871       break;
1872     case glass_TFCREATE:
1873       writable(msgs_lookup("tfCRT"),"",buff,tfile__create,t);
1874       break;
1875     case glass_TFGRAB:
1876       writable(msgs_lookup("tfGRAB"),"",buff,tfile__grabGetName,t);
1877       break;
1878     case glass_TFSHWSPR:
1879       gSprite_display(t);
1880       break;
1881     default:
1882       break;
1883   }
1884 }
1885
1886 /*
1887  * menu tfile__tfileMenuMaker(void *handle)
1888  *
1889  * Use
1890  *  Generates the menu for a template file window.
1891  *
1892  * Parameters
1893  *  void *handle == the template file window to deal with
1894  *
1895  * Returns
1896  *  A pointer to the menu structure to display.
1897  */
1898
1899 static menu tfile__tfileMenuMaker(void *handle)
1900 {
1901   static menu m;                 /* The main menu pointer                  */
1902   static menu disp;              /* Submenu for display options            */
1903   static menu windsm;            /* Submenu for window options             */
1904 #ifdef glass_NOTLAZY
1905   static menu stylesm;           /* Submenu for styles options             */
1906 #endif
1907   static char windName[50];      /* Buffer for window name                 */
1908   glass_tfile *t=handle;
1909   glass_windPointer *w;
1910
1911   if (!m)                        /* Do we have to create the menu?         */
1912   {
1913     m=menu_new("Glass",msgs_lookup("tfM"));
1914     disp=menu_new(msgs_lookup("tfDSPT"),
1915                   msgs_lookup("tfDSPM"));
1916     windsm=menu_new("_",msgs_lookup("tfWS"));
1917 #ifdef glass_NOTLAZY
1918     stylesm=menu_new(msgs_lookup("tfISST:Icon styles"),
1919                      msgs_lookup("tfISS:"
1920                                  "Edit style...,"
1921                                  "New style...,"
1922                                 ">Save..."));
1923 #endif
1924     menu_submenu(m,glass_TFSEL,windsm);
1925 #ifdef glass_NOTLAZY
1926     menu_submenu(m,glass_TFSTYLES,stylesm);
1927 #endif
1928     menu_submenu(m,glass_TFDISP,disp);
1929     menu_redirectItem(m,glass_TFSEL,windName,50,0);
1930   }
1931   menu_minWidth(m,0);
1932   viewer_setupMenu(t->v,
1933                    msgs_lookup("tfWIN"),
1934                    m,
1935                    glass_TFSEL,
1936                    windName);
1937   switch (viewer_selected(t->v))
1938   {
1939     case 0:
1940       menu_setflags(m,glass_TFCLRSEL,FALSE,TRUE);
1941       menu_setflags(m,glass_TFSELALL,FALSE,!viewer_icons(t->v));
1942       menu_settitle(windsm,msgs_lookup("tfWIN"));
1943       menu_setflags(windsm,glass_TFSELINFO,FALSE,TRUE);
1944       menu_setflags(windsm,glass_TFSELEDIT,FALSE,TRUE);
1945       menu_setflags(windsm,glass_TFSELCOPY,FALSE,TRUE);
1946       menu_setflags(windsm,glass_TFSELRENAME,FALSE,TRUE);
1947       menu_setflags(windsm,glass_TFSELSAVE,FALSE,TRUE);
1948       menu_setflags(windsm,glass_TFSELDELETE,FALSE,TRUE);
1949       break;
1950     case 1:
1951       w=viewer_iconHandle(viewer_firstSelected(t->v));
1952       menu_setflags(m,glass_TFCLRSEL,FALSE,FALSE);
1953       menu_setflags(m,glass_TFSELALL,FALSE,FALSE);
1954       menu_settitle(windsm,msgs_lookup("tfWIN"));
1955       menu_setflags(windsm,glass_TFSELINFO,FALSE,FALSE);
1956 #ifndef glass_DEMO
1957       menu_setflags(windsm,glass_TFSELEDIT,FALSE,w->testMode);
1958 #else
1959       menu_setflags(windsm,glass_TFSELEDIT,FALSE,FALSE);
1960 #endif
1961       menu_setflags(windsm,glass_TFSELCOPY,FALSE,FALSE);
1962       menu_setflags(windsm,glass_TFSELRENAME,FALSE,FALSE);
1963       menu_setflags(windsm,glass_TFSELSAVE,FALSE,FALSE);
1964       menu_setflags(windsm,glass_TFSELDELETE,FALSE,FALSE);
1965       break;
1966     default:
1967       menu_setflags(m,glass_TFCLRSEL,FALSE,FALSE);
1968       menu_setflags(m,glass_TFSELALL,FALSE,FALSE);
1969       menu_settitle(windsm,msgs_lookup("tfSEL"));
1970       menu_setflags(windsm,glass_TFSELINFO,FALSE,FALSE);
1971       menu_setflags(windsm,glass_TFSELEDIT,FALSE,TRUE);
1972       menu_setflags(windsm,glass_TFSELCOPY,FALSE,TRUE);
1973       menu_setflags(windsm,glass_TFSELRENAME,FALSE,TRUE);
1974       menu_setflags(windsm,glass_TFSELSAVE,FALSE,FALSE);
1975       menu_setflags(windsm,glass_TFSELDELETE,FALSE,FALSE);
1976       break;
1977   }
1978   menu_setflags(m,glass_TFSHWSPR,FALSE,!t->vs);
1979   menu_setflags(m,glass_TFGRAB,FALSE,window_grabbing());
1980   menu_setflags(disp,glass_TFDLARGE,t->isz==gPrefs_LARGE,FALSE);
1981   menu_setflags(disp,glass_TFDSMALL,t->isz==gPrefs_SMALL,FALSE);
1982   menu_setflags(disp,glass_TFDSORTNAME,t->sort==gPrefs_NAME,FALSE);
1983   menu_setflags(disp,glass_TFDSORTSIZE,t->sort==gPrefs_SIZE,FALSE);
1984   menu_setflags(disp,glass_TFDSORTICONS,t->sort==gPrefs_ICONS,FALSE);
1985   menu_setflags(disp,glass_TFDNOSORT,t->sort==gPrefs_NOSORT,FALSE);
1986   return (m);
1987 }
1988
1989 /*
1990  * void tfile__simMenu(glass_tfile *t,int hit1,int hit2)
1991  *
1992  * Use
1993  *  Simulates a menu hit on a template file window
1994  *
1995  * Parameters
1996  *  glass_tfile *t == the template file the event is destined for
1997  *  int hit1 == the main menu entry number
1998  *  int hit2 == the submenu entry number
1999  */
2000
2001 static void tfile__simMenu(glass_tfile *t,int hit1,int hit2)
2002 {
2003   wimp_menustr *m=menu_syshandle(tfile__tfileMenuMaker(t));
2004   wimp_menuitem *i=(wimp_menuitem *)(m+1)+(hit1-1);
2005   int mnu[3];
2006   mnu[0]=hit1;
2007   mnu[1]=hit2;
2008   mnu[2]=0;
2009
2010   if ((int)i->submenu==-1 || hit2==0)
2011   {
2012     if (i->iconflags & wimp_INOSELECT)
2013     {
2014       bbc_vdu(7);
2015       return;
2016     }
2017     else
2018       mnu[1]=0;
2019   }
2020   else
2021   {
2022     i=(wimp_menuitem *)(i->submenu+1)+(hit2-1);
2023     if (i->iconflags & wimp_INOSELECT)
2024     {
2025       bbc_vdu(7);
2026       return;
2027     }
2028   }
2029   tfile__tfileMenuHandler(mnu,t);
2030 }
2031
2032 /*
2033  * BOOL tfile__dragUnknowns(wimp_eventstr *e,void *handle)
2034  *
2035  * Use
2036  *  Handles unknown events during the period of dragging viewer icons
2037  *  around.  It will respond to the following drags:
2038  *
2039  *  A drag to a blank area of icon bar will open the windows.
2040  *
2041  *  Otherwise, a selection save will be started, and the windows packaged
2042  *  off to another application.
2043  *
2044  * Parameters
2045  *  wimp_eventstr *e == the event to look at
2046  *  void *handle == the template file we're dragging from
2047  *
2048  * Returns
2049  *  TRUE if the drag has been processed
2050  */
2051
2052 static BOOL tfile__dragUnknowns(wimp_eventstr *e,void *handle)
2053 {
2054   glass_tfile *t=handle;
2055   wimp_mousestr m;
2056   BOOL handled=FALSE;
2057   switch (e->e)
2058   {
2059     case wimp_EUSERDRAG:
2060       handled=TRUE;
2061       win_remove_unknown_event_processor(tfile__dragUnknowns,t);
2062       wimpt_noerr(wimp_get_point_info(&m));
2063       if (m.w==viewer_syshandle(t->v))
2064         break;
2065       if (m.w==-2 && m.i==-1)
2066         viewer_doForIcons(t->v,TRUE,tfile__openWindows);
2067       else
2068       {
2069           tfile__selectSize=0;
2070           viewer_doForIcons(t->v,TRUE,tfile__size);
2071           wimpt_fake_event(e);          /* Fool xfersend to send data      */
2072           xfersend(0xFEC,
2073                    msgs_lookup("tfSEL"),
2074                    tfile__selectSize,
2075                    tfile__saveSelection,
2076                    tfile__sendSelection,
2077                    0,
2078                    e,
2079                    t);
2080       }
2081       viewer_selectAll(t->v,FALSE);
2082       break;
2083   }
2084   return (handled);
2085 }
2086
2087 /*
2088  * BOOL tfile__raw(viewer v,wimp_eventstr *e,void *handle)
2089  *
2090  * Use
2091  *  Handles intMsgs from other parts of the system
2092  *
2093  * Parameters
2094  *  viewer v == the handle for the viewer window
2095  *  wimp_eventstr *e == the event to process
2096  *  void *handle == the template file
2097  *
2098  * Returns
2099  *  TRUE if event was processed
2100  */
2101
2102 static BOOL tfile__raw(viewer v,wimp_eventstr *e,void *handle)
2103 {
2104   BOOL handled=FALSE;
2105   char *filename;
2106   int estsize;
2107   int filetype;
2108   void *p;
2109   glass_tfile *t=handle;
2110   int at;
2111   switch (e->e)
2112   {
2113     case wimp_EKEY:
2114       switch (e->data.key.chcode)
2115       {
2116         case akbd_Fn+1+akbd_Sh: /* sF1 */
2117           tfile__simMenu(t,glass_TFINFO,0);
2118           handled=TRUE;
2119           break;
2120         case 1:                 /* ^A */
2121           tfile__simMenu(t,glass_TFSELALL,0);
2122           handled=TRUE;
2123           break;
2124         case 26:                /* ^Z */
2125           tfile__simMenu(t,glass_TFCLRSEL,0);
2126           handled=TRUE;
2127           break;
2128         case akbd_Fn+3:         /* F3 */
2129           tfile__simMenu(t,glass_TFSAVE,0);
2130           handled=TRUE;
2131           break;
2132         case 14:                /* ^N */
2133           tfile__simMenu(t,glass_TFCREATE,0);
2134           handled=TRUE;
2135           break;
2136         case 7:                 /* ^G */
2137           tfile__simMenu(t,glass_TFGRAB,0);
2138           handled=TRUE;
2139           break;
2140         case 19:                /* ^S */
2141           tfile__simMenu(t,glass_TFSHWSPR,0);
2142           handled=TRUE;
2143           break;
2144
2145         case akbd_Fn+5:         /* F5 */
2146           tfile__simMenu(t,glass_TFDISP,glass_TFDLARGE);
2147           handled=TRUE;
2148           break;
2149         case akbd_Fn+5+akbd_Sh: /* sF5 */
2150           tfile__simMenu(t,glass_TFDISP,glass_TFDSMALL);
2151           handled=TRUE;
2152           break;
2153         case akbd_Fn+6:         /* F6 */
2154           tfile__simMenu(t,glass_TFDISP,glass_TFDSORTNAME);
2155           handled=TRUE;
2156           break;
2157         case akbd_Fn+6+akbd_Sh: /* sF6 */
2158           tfile__simMenu(t,glass_TFDISP,glass_TFDSORTSIZE);
2159           handled=TRUE;
2160           break;
2161         case akbd_Fn+6+akbd_Ctl:/* ^F6 */
2162           tfile__simMenu(t,glass_TFDISP,glass_TFDSORTICONS);
2163           handled=TRUE;
2164           break;
2165         case akbd_Fn+6+akbd_Ctl+akbd_Sh:/* s^F6 */
2166           tfile__simMenu(t,glass_TFDISP,glass_TFDNOSORT);
2167           handled=TRUE;
2168           break;
2169
2170         case akbd_Fn+1+akbd_Ctl:/* ^F1 */
2171           tfile__simMenu(t,glass_TFSEL,glass_TFSELINFO);
2172           handled=TRUE;
2173           break;
2174         case 5:                 /* ^E */
2175           tfile__simMenu(t,glass_TFSEL,glass_TFSELEDIT);
2176           handled=TRUE;
2177           break;
2178         case 3:                 /* ^C */
2179           tfile__simMenu(t,glass_TFSEL,glass_TFSELCOPY);
2180           handled=TRUE;
2181           break;
2182         case 18:                /* ^R */
2183           tfile__simMenu(t,glass_TFSEL,glass_TFSELRENAME);
2184           handled=TRUE;
2185           break;
2186         case akbd_Fn+3+akbd_Sh: /* sF3 */
2187           tfile__simMenu(t,glass_TFSEL,glass_TFSELSAVE);
2188           handled=TRUE;
2189           break;
2190         case 24:                /* ^X */
2191           tfile__simMenu(t,glass_TFSEL,glass_TFSELDELETE);
2192           handled=TRUE;
2193           break;
2194
2195         case akbd_Fn+2+akbd_Ctl:/* ^F2 */
2196           tfile__close(t,FALSE);
2197           handled=TRUE;
2198           break;
2199       }
2200       break;
2201     case wimp_ESEND:
2202     case wimp_ESENDWANTACK:
2203       switch (e->data.msg.hdr.action)
2204       {
2205         case wimp_MDATASAVE:
2206           filetype=xferrecv_checkimport(&estsize);
2207           switch (filetype)
2208           {
2209             case 0xfec:          /* Template files                         */
2210               if (xferrecv_returnImportedBlock(&p)!=-1)
2211               {
2212                 tfile_markAsAltered(t);
2213                 tfile_mergeFromMemory(&p,t);
2214                 flex_free(&p);
2215               }
2216               break;
2217             case 0xff9:          /* Sprite files (I think)                 */
2218               if (t->vs)
2219               {
2220                 if (xferrecv_returnImportedBlock(&p)!=-1)
2221                 {
2222                   gSprite_mergeFromMemory(t,&p);
2223                   flex_free(&p);
2224                 }
2225               }
2226               break;
2227           }
2228           break;
2229         case wimp_MDATALOAD:
2230           filetype=xferrecv_checkinsert(&filename);
2231           switch (filetype)
2232           {
2233             case 0xfec:          /* Template files                         */
2234               tfile_mergeFromFile(filename,t);
2235               tfile_markAsAltered(t);
2236               xferrecv_insertfileok();
2237               break;
2238             case 0xff9:          /* Sprite files (I think)                 */
2239               if (t->vs)
2240               {
2241                 gSprite_mergeFromFile(t,filename);
2242                 xferrecv_insertfileok();
2243               }
2244               break;
2245           }
2246           break;
2247         case wimp_MINTERNAL:
2248           switch (e->data.msg.data.words[0])
2249           {
2250             case glass_KILLFILES:
2251               tfile__deleteTemplateFile(t);
2252               break;
2253             case glass_CLOSEDOWN:
2254               viewer_doForIcons(v,FALSE,tfile__tidyFonts);
2255               handled=TRUE;
2256               break;
2257             case glass_MODECHANGE:
2258               viewer_doForIcons(v,FALSE,tfile__reFindFonts);
2259               handled=TRUE;
2260               break;
2261             case glass_AUTOSAVE:
2262               if (t->autoAlarm)
2263                 alarm_remove(t->autoAlarm,t);
2264               t->autoAlarm=0;
2265               if (t->autoTime)
2266               {
2267                 if (at=gPrefs_autoTiming(),at)
2268                 {
2269                   t->autoAlarm=t->autoTime+at;
2270                   alarm_set(t->autoAlarm,tfile__doAutosave,t);
2271                 }
2272               }
2273               if (gPrefs_current()->aAlts!=0 &&
2274                   t->alts>=gPrefs_current()->aAlts)
2275                 tfile__doAutosave(0,t);
2276               break;
2277           }
2278           break;
2279       }
2280       break;
2281   }
2282   return (handled);
2283 }
2284
2285 /*
2286  * void tfile__tfileHandler(viewer v,
2287  *                          viewer_icon i,
2288  *                          wimp_bbits b,
2289  *                          void *vhandle,
2290  *                          void *ihandle)
2291  *
2292  * Use
2293  *  Handles events for a template file window (including things like menu
2294  *  clicks).
2295  *
2296  * Parameters
2297  *  viewer v == the viewer that the event happened to
2298  *  viewer_icon i == the icon it happened to
2299  *  wimp_bbits b == the mouse button status
2300  *  void *vhandle == pointer to the template file structure
2301  *  void *ihandle == pointer to the window pointer structure
2302  */
2303
2304 static void tfile__tfileHandler(viewer v,
2305                                 viewer_icon i,
2306                                 wimp_bbits b,
2307                                 void *vhandle,
2308                                 void *ihandle)
2309 {
2310   glass_tfile *t=vhandle;
2311   glass_windPointer *wp=ihandle;
2312   switch ((int)i)
2313   {
2314     case (int)viewer_CLOSE:      /* If the user closes the window          */
2315       tfile__close(t,TRUE);      /*  Try to close it :-)                   */
2316       break;
2317     case (int)viewer_HELP:       /* Help request for the window            */
2318       help_startHelp();          /* Prepare a reply                        */
2319       help_addLine(msgs_lookup("tfhTF"));
2320       help_endHelp();            /* Send the message to Help application   */
2321       break;
2322     default:
2323       if (b!=wimp_BMID)
2324       {
2325         tfile__gainSelection(t);
2326         viewer_clickSelect(v,i,b);
2327       }
2328       switch (b)
2329       {
2330         case wimp_BMID:
2331           if (t==tfile__selOwner ||
2332               !tfile__selOwner ||
2333               !viewer_selected(tfile__selOwner->v) )
2334           {
2335             tfile__selOwner=t;
2336             viewer_clickSelect(v,i,b);
2337           }
2338           menu_make(tfile__tfileMenuMaker,
2339                     tfile__tfileMenuHandler,
2340                     tfile__tfileMenuHelp,
2341                     t);
2342           break;
2343         case wimp_BLEFT:
2344           if (i!=viewer_NOICON)
2345           {
2346             if (akbd_pollsh() && wp->h)
2347               window_close(wp);
2348             else
2349               window_open(wp,FALSE); /* Open the window on-screen          */
2350             viewer_selectIcon(i,FALSE); /* And deslect the icon            */
2351           }
2352           break;
2353         case wimp_BRIGHT:
2354           if (i!=viewer_NOICON)
2355           {
2356             if (akbd_pollsh() && wp->h)
2357               window_close(wp);
2358             else
2359               window_open(wp,TRUE); /* Open the window on-screen           */
2360             viewer_selectIcon(i,FALSE); /* And deslect the icon            */
2361           }
2362           break;
2363         case wimp_BDRAGLEFT:
2364         case wimp_BDRAGRIGHT:
2365           if (i!=viewer_NOICON)
2366           {
2367             tfile_dragSelected(i,b,"tpackage");
2368             win_add_unknown_event_processor(tfile__dragUnknowns,t);
2369           }
2370           break;
2371       }
2372       break;
2373   }
2374 }
2375
2376 /*----- External routines -------------------------------------------------*/
2377
2378 /*
2379  * BOOL tfile_okToQuit(BOOL ask)
2380  *
2381  * Use
2382  *  Ensures that it is 'safe' for Glass to quit.
2383  *
2384  * Parameters
2385  *  BOOL ask == should I open a dialogue to ask the user?
2386  *
2387  * Returns
2388  *  TRUE if it is safe to quit, or FALSE if not.
2389  */
2390
2391 BOOL tfile_okToQuit(BOOL ask)
2392 {
2393   char *q;
2394   if (tfile__unsavedFiles==0 || !gPrefs_current()->cQuit)
2395     return (TRUE);
2396   else if (ask==FALSE)
2397     return (FALSE);
2398   else if (tfile__unsavedFiles==1)
2399     q=msgs_lookup("tfOTQ1");
2400   else
2401     q=msgs_lookup("tfOTQM");
2402   return (warning(msgs_lookup("tfOTQP"),q,tfile__unsavedFiles));
2403 }
2404
2405 /*
2406  * void tfile_markAsAltered(glass_tfile *t)
2407  *
2408  * Use
2409  *  Marks down another alteration for the template file, changing the window
2410  *  title if required etc.  Also handles stuff for autosave etc.
2411  *
2412  * Parameters
2413  *  glass_tfile *t == the template file to alter
2414  */
2415
2416 void tfile_markAsAltered(glass_tfile *t)
2417 {
2418   char buff[256];
2419   int at;
2420   t->alts++;
2421   if (t->alts==1 || t->alts==0)
2422   {
2423     sprintf(buff,"%s *",t->filename);
2424     viewer_settitle(t->v,buff);
2425     if (t->alts==1)
2426       tfile__unsavedFiles++;
2427     t->alts=1;
2428   }
2429   if (t->sort==gPrefs_SIZE || t->sort==gPrefs_ICONS)
2430     viewer_setCompare(t->v,tfile__sort);
2431   if (!t->autoTime)
2432   {
2433     t->autoTime=alarm_timenow();
2434     if (at=gPrefs_autoTiming(),at)
2435     {
2436       t->autoAlarm=t->autoTime+at;
2437       alarm_set(t->autoAlarm,tfile__doAutosave,t);
2438     }
2439     else
2440       t->autoAlarm=0;
2441   }
2442   if (gPrefs_current()->aAlts!=0 && t->alts>=gPrefs_current()->aAlts)
2443     tfile__doAutosave(0,t);
2444 }
2445
2446 /*
2447  * void tfile_markAsSaved(glass_tfile *t,char *newTitle)
2448  *
2449  * Use
2450  *  Marks a template file as having been saved.  Turns off autosave and
2451  *  things.
2452  *
2453  * Parameters
2454  *  glass_tfile *t == the file to mark
2455  *  char *newtitle == the new title to give to the window
2456  */
2457
2458 void tfile_markAsSaved(glass_tfile *t,char *newTitle)
2459 {
2460   char buff[256];
2461   if (t->alts)
2462   {
2463     t->alts=0;
2464     tfile__unsavedFiles--;
2465   }
2466   t->loaded=TRUE;
2467   strcpy(t->filename,newTitle);
2468   viewer_settitle(t->v,newTitle);
2469   intMsgs_send(glass_SAVEFILE,t);
2470   if (t->vs)
2471   {
2472     sprintf(buff,msgs_lookup("spVT"),newTitle);
2473     viewer_settitle(t->vs,buff);
2474   }
2475   if (t->autoAlarm)
2476     alarm_remove(t->autoAlarm,t);
2477   t->autoAlarm=0;
2478   t->autoTime=0;
2479   if (t->autod)
2480   {
2481     dbox_deleteNoUpdate(t->autod);
2482     t->autoSaved=TRUE;
2483     t->autod=0;
2484   }
2485 }
2486
2487 /*
2488  * void tfile_windowInfo(glass_windPointer *w)
2489  *
2490  * Use
2491  *  Displays an info box for a single window
2492  *
2493  * Parameters
2494  *  glass_windPointer *w == the window to display info on
2495  */
2496
2497 void tfile_windowInfo(glass_windPointer *w)
2498 {
2499   dbox d=dbox_create("windInfo");
2500   if (!d)
2501     return;
2502   dbox_setfield(d,glass_WINAME,"%s",w->id);
2503   dbox_setfield(d,glass_WISIZE,"%s",utils_cvtSize(w->size));
2504   dbox_setfield(d,
2505                 glass_WIINDSZ,
2506                 "%s",
2507                 utils_cvtSize(w->size-
2508                               sizeof(glass_window)-
2509                               (w->def->desc.w.nicons-1)*
2510                                    sizeof(glass_iconDescription)));
2511   dbox_setfield(d,glass_WIICONS,"%i",w->def->desc.w.nicons);
2512   mbox(d,"tfhWI");
2513 }
2514
2515 /*
2516  * void tfile_deleteWindow(glass_windPointer *w)
2517  *
2518  * Use
2519  *  Deletes a single window.
2520  *
2521  * Parameters
2522  *  viewer_icon i == the icon to get
2523  *  void *handle ==  the window to eliminate (as a glass_windPointer *)
2524  */
2525
2526 void tfile_deleteWindow(viewer_icon i,void *handle)
2527 {
2528   glass_windPointer *w=handle;
2529   unused(i);
2530   intMsgs_send(glass_DELETEWINDOW,w);
2531   viewer_removeIcon(w->i);
2532   tfile__doDeleteWindow(w);
2533 }
2534
2535 /*
2536  * BOOL tfile_rename(char *newName,void *handle)
2537  *
2538  * Use
2539  *  Renames the specified window
2540  *
2541  * Parameters
2542  *  char *newName == the new name of the window
2543  *  void *handle == pointer to the window structure
2544  */
2545
2546 BOOL tfile_rename(char *newName,void *handle)
2547 {
2548   glass_windPointer *w=handle;
2549   viewer_icon i;
2550   if (strcmp(newName,w->id)==0)
2551     return (TRUE);
2552   i=viewer_findIcon(w->t->v,newName);
2553   if (i==viewer_NOICON || i==w->i)
2554   {
2555     viewer_removeIcon(w->i);
2556     mem_useUser(indir_alloc,indir_free);
2557     strcpy(w->id,newName);
2558     i=viewer_addIcon(w->t->v,newName,"tmpltvicon",TRUE,w);
2559     viewer_setFiletype(i,0xfec);
2560     mem_useMalloc();
2561     w->i=i;
2562     intMsgs_send(glass_RENAME,w);
2563     tfile_markAsAltered(w->t);
2564     event_clear_current_menu();
2565     return (TRUE);
2566   }
2567   note(msgs_lookup("tfNAE"),
2568        viewer_textOfIcon(i));
2569   return (FALSE);
2570 }
2571
2572 /*
2573  * void tfile_saveTemplates(glass_tfile *t)
2574  *
2575  * Use
2576  *  Saves a template file using a standard dialogue box
2577  *
2578  * Parameters
2579  *  glass_tfile *t == the template file to save
2580  */
2581
2582 void tfile_saveTemplates(glass_tfile *t)
2583 {
2584   char *name;
2585   if (t->loaded)
2586     name=t->filename;
2587   else
2588     name=msgs_lookup("tfTMP");
2589   tfile__selectSize=0;
2590   viewer_doForIcons(t->v,FALSE,tfile__size);
2591   saveas(msgs_lookup("tfSVTIT"),
2592          name,
2593          0xfec,
2594          tfile__selectSize,
2595          tfile__saveTemplates,
2596          tfile__sendTemplates,
2597          0,
2598          t);
2599 }
2600
2601 /*
2602  * void tfile_saveWindow(glass_windPointer *w)
2603  *
2604  * Use
2605  *  Saves a single window using a standard dialogue box
2606  *
2607  * Parameters
2608  *  glass_windPointer *w == pointer to the window to save
2609  */
2610
2611 void tfile_saveWindow(glass_windPointer *w)
2612 {
2613   tfile__selectSize=w->size;
2614   saveas(msgs_lookup("tfSVWTIT"),
2615          msgs_lookup("tfWIN"),
2616          0xfec,
2617          w->size,
2618          tfile__saveWindow,
2619          tfile__sendWindow,
2620          0,
2621          w);
2622 }
2623
2624 /*
2625  * BOOL tfile_mergeFromMemory(void **p,glass_tfile *t)
2626  *
2627  * Use
2628  *  Actually does a merge operation.  The target file is a glass_tfile in
2629  *  memory (internal format) and the source file is a memory image of a
2630  *  normal template file.
2631  *
2632  * Parameters
2633  *  void **p == a flex anchor pointer to the source file
2634  *  glass_tfile *t == a pointer to the destination file
2635  *
2636  * Returns
2637  *  TRUE for success
2638  */
2639
2640 typedef struct { char **p; int offset; } tfile__datPackage;
2641
2642 static char *tfile__dataProc(char *data,void *handle)
2643 {
2644   tfile__datPackage *p=handle;
2645   return (((int)data)+*(p->p)+p->offset);
2646 }
2647
2648 BOOL tfile_mergeFromMemory(void **p,glass_tfile *t)
2649 {
2650   int fontData;                  /* Offset of font ata from start of file  */
2651   glass_windPointer *w;          /* For each window we come across         */
2652   int index;                     /* Current index entry we're looking at   */
2653   int objoff;                    /* Offset of window we're looking at      */
2654   int iconoff;                   /* Offset of icon we're looking at        */
2655   wimp_iconflags icf;            /* Icon flags for something or other      */
2656   int fheight;                   /* Height of a font required              */
2657   int fwidth;                    /* Width of a font required               */
2658   int fhandle;                   /* Font handle                            */
2659   int fptr;                      /* Offset of font name                    */
2660   char name[13];                 /* For the name of the template           */
2661
2662   int objtype;                   /* Type of current template entry         */
2663   BOOL foundOdd=FALSE;           /* Found an odd type of data yet?         */
2664   int numicons;                  /* Number of icons in a window            */
2665   int i;                         /* A loop counter                         */
2666   viewer_icon icn;               /* Icon for checking for duplicates       */
2667   BOOL fquiet=FALSE;             /* Shut up about font failures.           */
2668   tfile__datPackage pk;
2669
2670   fontData=*intptr(*p,0);        /* Offset of font data from *p            */
2671   for (index=16;*intptr(*p,index);index+=24) /* Go through index entries   */
2672   {
2673     objoff=*intptr(*p,index);    /* Offset of this entry                   */
2674     objtype=*intptr(*p,index+8); /* Type of this entry                     */
2675     switch (objtype)             /* Which type is it?                      */
2676     {
2677       case 1:                    /* Window                                 */
2678         pk.p=(char **)p;
2679         pk.offset=objoff;
2680
2681         memcpy(name,charptr(*p,index+12),12);
2682         name[12]=0;
2683         utils_ctermToNterm(name);
2684         if (icn=viewer_findIcon(t->v,name),icn)
2685           tfile_deleteWindow(icn,viewer_iconHandle(icn));
2686         if (w=tfile__newWindow(t,name),!w)
2687           return (FALSE);        /* Failed to create the window            */
2688         memcpy(&numicons,intptr(*p,objoff+84),sizeof(int));
2689         w->size=sizeof(glass_window)+
2690                 (numicons-1)*sizeof(glass_iconDescription);
2691         if (!flex_alloc((flex_ptr)&w->def,w->size))
2692         {
2693           viewer_removeIcon(w->i);
2694           mem_free(w);
2695           werr(FALSE,msgs_lookup("tfNEMTL"));
2696           return (FALSE);
2697         }
2698         memcpy(&w->def->desc.w,_ptr(void,*p,objoff),sizeof(wimp_wind));
2699         icf=w->def->desc.w.titleflags; /* Get title icon flags             */
2700         if (icf & wimp_IFONT)    /* Handle anti-aliased fonts              */
2701         {
2702           fhandle=(icf & 0xff000000) >> 24; /* Get internal font handle    */
2703           fptr=fontData+(fhandle-1)*48; /* Get pointer                     */
2704           /* Bug fix - not word aligned!! */
2705           memcpy(&fwidth,intptr(*p,fptr)+0,sizeof(int));
2706           memcpy(&fheight,intptr(*p,fptr)+1,sizeof(int));
2707           utils_ctermToNterm(charptr(*p,fptr+8)); /* Font name             */
2708           if (font_find(charptr(*p,fptr+8),fwidth,fheight,0,0,&fhandle))
2709           {
2710             if (!fquiet)
2711             {
2712               werr(FALSE,msgs_lookup("tfCFF"));
2713               fquiet=TRUE;
2714             }
2715             icf&=~wimp_IFONT;    /* Stop anti-aliasing (gives odd colours) */
2716           }
2717           else
2718           {
2719             icf=(icf & 0x00ffffff) | (fhandle << 24);
2720             w->antiAliased=TRUE;
2721             w->fonts[fhandle]++;
2722           }
2723           w->def->desc.w.titleflags=icf;
2724         }
2725         w->def->desc.w.nicons=0; /* Don't want deletion routine dying      */
2726         if (!iconData_processIcon(w,-1,tfile__dataProc,TRUE,&pk))
2727         {
2728           werr(FALSE,msgs_lookup("tfNEMTL"));
2729           tfile_deleteWindow(0,w);
2730           return (FALSE);
2731         }
2732         iconoff=objoff+88;       /* Point to first icon definition         */
2733         for (i=0;i<numicons;i++)
2734         {
2735           memcpy(&w->def->i[i].i,charptr(*p,iconoff),sizeof(wimp_icon));
2736           w->def->i[i].selected=FALSE;
2737           w->def->i[i].edit=0;
2738           icf=w->def->i[i].i.flags; /* Get title icon flags                */
2739           if (icf & wimp_IFONT)  /* Handle anti-aliased fonts              */
2740           {
2741             fhandle=(icf & 0xff000000) >> 24; /* Get internal font handle  */
2742             fptr=fontData+(fhandle-1)*48; /* Get pointer                   */
2743             /* Bug fix - not word aligned!! */
2744             memcpy(&fwidth,intptr(*p,fptr)+0,sizeof(int));
2745             memcpy(&fheight,intptr(*p,fptr)+1,sizeof(int));
2746             utils_ctermToNterm(charptr(*p,fptr+8)); /* Font name           */
2747             if (font_find(charptr(*p,fptr+8),fwidth,fheight,0,0,&fhandle))
2748             {
2749               if (!fquiet)
2750               {
2751                 werr(FALSE,msgs_lookup("tfCFF"));
2752                 fquiet=TRUE;
2753               }
2754               icf&=~wimp_IFONT;    /* Stop anti-aliasing                   */
2755             }
2756             else
2757             {
2758               icf=(icf & 0x00ffffff) | (fhandle << 24);
2759               w->antiAliased=TRUE;
2760               w->fonts[fhandle]++;
2761             }
2762             w->def->i[i].i.flags=icf;
2763           }
2764           if (!iconData_processIcon(w,i,tfile__dataProc,TRUE,&pk))
2765           {
2766             werr(FALSE,msgs_lookup("tfNEMTL"));
2767             tfile_deleteWindow(0,w);
2768             return (FALSE);
2769           }
2770           w->def->desc.w.nicons++; /* Tidy up next icon along              */
2771           iconoff+=sizeof(wimp_icon); /* Move pointer along                */
2772         }
2773         break;
2774       default:                   /* Anything we don't know - tell the user */
2775         if (!foundOdd)           /* Don't generate the message again       */
2776         {
2777           werr(FALSE,msgs_lookup("tfUTEC"));
2778           foundOdd=TRUE;         /* Stop message repeating                 */
2779         }
2780         break;
2781     }
2782   }
2783   return (TRUE);
2784 }
2785
2786 /*
2787  * BOOL tfile_mergeFromFile(char *file,glass_tfile *t)
2788  *
2789  * Use
2790  *  Merges the template file given into the given template file structure.
2791  *
2792  * Parameters
2793  *  char *file == the file to load
2794  *  glass_tfile *t == the template file structure to merge with
2795  */
2796
2797 BOOL tfile_mergeFromFile(char *file,glass_tfile *t)
2798 {
2799   os_filestr f;                  /* Going to make some OS_File calls       */
2800   void *p;                       /* p will point to the file in memory     */
2801   f.action=17;                   /* Read catalogue information for file    */
2802   f.name=file;                   /* Point to file name to find out about   */
2803   if (utils_complain(os_file(&f),
2804       msgs_lookup("tfELF")))
2805   {
2806     return (FALSE);
2807   }
2808   if (!flex_alloc(&p,f.start))
2809   {
2810     werr(FALSE,msgs_lookup("tfNEMTL"));
2811     return (FALSE);
2812   }
2813   f.action=16;                   /* Load the file                          */
2814   f.loadaddr=(int)p;             /* Where to load the file                 */
2815   f.execaddr=0;                  /* Load it there!!!                       */
2816   if (utils_complain(os_file(&f),
2817       msgs_lookup("tfELF")))
2818   {
2819     flex_free(&p);
2820     flex_compact();
2821     return (FALSE);
2822   }
2823   tfile_mergeFromMemory(&p,t);   /* Now do the merge                       */
2824   flex_free(&p);
2825   flex_compact();
2826   return (TRUE);
2827 }
2828
2829 /*
2830  * glass_tfile *tfile_createTemplateFile(char *name)
2831  *
2832  * Use
2833  *  Creates a template file with the given name, but doesn't open its viewer.
2834  *
2835  * Returns
2836  *  A pointer to the file structure, or zero as failure.
2837  */
2838
2839 glass_tfile *tfile_createTemplateFile(char *name)
2840 {
2841   glass_tfile *t;
2842   int ix,iy;
2843   mem_useUser(indir_alloc,indir_free);
2844   t=mem_alloc(sizeof(glass_tfile));
2845   if (!t)                        /* Allocates memory for file structure    */
2846   {
2847     werr(FALSE,msgs_lookup("tfNEMTF"));
2848     mem_useMalloc();
2849     return (0);
2850   }
2851   ix=(gPrefs_current()->fIcons==gPrefs_LARGE) ? 200 : 248;
2852   iy=(gPrefs_current()->fIcons==gPrefs_LARGE) ? 112 : 36;
2853   if
2854   (
2855     t->v=viewer_create           /* Now create the viewer window           */
2856     (
2857       tfile__FILEX,              /* Coords to open window                  */
2858       tfile__fileHeight,
2859       ix,                        /* Width of 'icons'                       */
2860       iy,                        /* Height of 'icons'                      */
2861       resspr_area(),             /* Sprite area for 'icons'                */
2862       name,                      /* What to display in the title bar       */
2863       msgs_lookup("tfBANR") /* Viewer banner line     */
2864     ),
2865     !t->v                        /* TRUE if creation failed                */
2866   )
2867   {
2868     mem_free(t);                 /* Dispose of unwanted file structure     */
2869     mem_useMalloc();
2870     return (0);                  /* Inform caller we buggered it up        */
2871   }
2872   mem_useMalloc();
2873   strcpy(t->filename,name);      /* Remember the name                      */
2874   t->alts=0;                     /* No alterations yet                     */
2875   t->loaded=FALSE;               /* They can change this if they need to   */
2876   t->autoSaved=FALSE;            /* Not been autosaved yet                 */
2877   t->autod=0;                    /* No autosave dialogue box               */
2878   t->autoTime=0;                 /* No autosave time                       */
2879   t->autoAlarm=0;                /* No autosave alarm                      */
2880   t->isz=gPrefs_current()->fIcons;
2881   t->sort=gPrefs_current()->fSort;
2882   viewer_eventHandler(t->v,tfile__tfileHandler,t); /* Add event handler    */
2883   viewer_rawEventHandler(t->v,tfile__raw,t); /* Raw, for broadcasts        */
2884   viewer_redrawHandler(t->v,
2885                        t->isz==gPrefs_LARGE ? 0 : tfile__redrawViewer,
2886                        t);
2887   viewer_setCompare(t->v,tfile__sort);
2888   tfile__fileHeight-=48;         /* Displace the next file window          */
2889   if (tfile__fileHeight<652)     /* Start at the top again if too low      */
2890     tfile__fileHeight=tfile__FILETOP;
2891   gSprite_new(t);
2892   return (t);
2893 }
2894
2895 /*
2896  * glass_tfile *tfile_loadFromMemory(void **p,char *name)
2897  *
2898  * Use
2899  *  Loads a file from memory, i.e. from another application via RAM
2900  *  transfer.
2901  *
2902  * Parameters
2903  *  void **p == the memory block that contains the file to load.
2904  *  char *name == the name to give to the file.
2905  *
2906  * Returns
2907  *  A pointer to the template file, or 0
2908  */
2909
2910 glass_tfile *tfile_loadFromMemory(void **p,char *name)
2911 {
2912   glass_tfile *t=tfile_createTemplateFile(name);
2913   if (!t)
2914     return (0);
2915   t->loaded=TRUE;
2916   if (!tfile_mergeFromMemory(p,t))
2917   {
2918     tfile__deleteTemplateFile(t);
2919     return (0);
2920   }
2921   if (t->sort==gPrefs_SIZE || t->sort==gPrefs_ICONS)
2922     viewer_setCompare(t->v,tfile__sort);
2923   viewer_display(t->v);          /* Show the viewer window in its glory    */
2924   return (t);
2925 }
2926
2927 /*
2928  * glass_tfile *tfile_loadFromFile(char *file,char *name)
2929  *
2930  * Use
2931  *  Loads a template file into memory, translating the file into Glass's
2932  *  internal format.  It does not create any windows, although it does
2933  *  allocate font handles.
2934  *
2935  * Parameters
2936  *  char *file == the name of the file to load
2937  *  char *name == the name to insert in the title bar
2938  *
2939  * Returns
2940  *  A pointer to the structure definition, or 0 for failure.  Note that this
2941  *  will only occur if no windows could be loaded.
2942  */
2943
2944 glass_tfile *tfile_loadFromFile(char *file,char *name)
2945 {
2946   glass_tfile *t=tfile_createTemplateFile(name);
2947   char buff[256];
2948   char fbuff[256];
2949   char *parent;
2950   if (!t)
2951     return (0);
2952   t->loaded=TRUE;
2953   if (!tfile_mergeFromFile(file,t))
2954   {
2955     tfile__deleteTemplateFile(t);
2956     return (0);
2957   }
2958   strcpy(fbuff,name);
2959   utils_leafname(fbuff)[-1]=0;
2960   parent=utils_leafname(fbuff);
2961   parent[-1]=0;
2962   if (gPrefs_current()->sLoadPSpr)
2963   {
2964     sprintf(buff,"%s.%s.!Sprites",fbuff,parent);
2965     if (res_fileExists(buff))
2966       gSprite_mergeFromFile(t,buff);
2967     else
2968     {
2969       sprintf(buff,"%s.!Sprites",fbuff);
2970       if (res_fileExists(buff))
2971         gSprite_mergeFromFile(t,buff);
2972     }
2973   }
2974   if (gPrefs_current()->sLoadSpr)
2975   {
2976     sprintf(buff,"%s.%s.Sprites",fbuff,parent);
2977     if (res_fileExists(buff))
2978       gSprite_mergeFromFile(t,buff);
2979   }
2980   viewer_display(t->v);          /* Show the viewer window in its glory    */
2981   return (t);
2982 }
2983
2984 /*
2985  * void tfile_dragSelected(viewer_icon i,wimp_bbits b,char *package)
2986  *
2987  * Use
2988  *  As for viewer_dragSelected, but uses the specified sprite as the
2989  *  'package' sprite is solid sprite drags are enabled.
2990  *
2991  * Parameters
2992  *  viewer_icon i == the icon to drag
2993  *  wimp_bbits b == the button status that started it off
2994  *  char *package == the sprite to use for a package drag
2995  */
2996
2997 void tfile_dragSelected(viewer_icon i,wimp_bbits b,char *package)
2998 {
2999   sprite_id sid;
3000   sid.s.name=package;
3001   sid.tag=0;
3002   sprite_rename(resspr_area(),&sid,"package");
3003   viewer_dragSelected(i,b);
3004   sid.s.name="package";
3005   sprite_rename(resspr_area(),&sid,package);
3006 }