chiark / gitweb /
Initial revision
[ssr] / StraySrc / Glass / !Glass / c / glass
1 /*
2  * glass.c
3  *
4  * Main control section and user interface
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 #include <stddef.h>
38 #include <time.h>
39
40 #include "dll.h"
41
42 /*
43  * Steel headers
44  */
45
46 #define _STDAPP
47 #define _XFER
48 #define _LOWLVL
49 #include "steel/Steel.h"
50
51 #include "steel/viewer.h"
52 #include "steel/mem.h"
53 #include "steel/caretptr.h"
54 #include "steel/buttons.h"
55 #include "steel/sculptrix.h"
56 #include "steel/flex.h"
57
58 /*
59  * Glass headers
60  */
61
62 #include "gStruct.h"
63 #include "gIcons.h"
64 #include "gMenus.h"
65
66 #include "glass.h"
67 #include "toolbox.h"
68 #include "tfile.h"
69 #include "intMsgs.h"
70 #include "gPrefs.h"
71 #include "gSprite.h"
72 #include "indir.h"
73 #include "window.h"
74 #include "tearEdit.h"
75
76 /*----- External dependencies ---------------------------------------------*/
77
78 extern char date[], cright[];
79 #define VERSION 100
80
81 /*----- Static global variables -------------------------------------------*/
82
83 static BOOL glass_genDump;           /* Send timings to dump (stderr)      */
84 static BOOL glass_noWindow;          /* Turn off the nice intro window     */
85
86 /*----- Icon bar handlers -------------------------------------------------*/
87
88 /*
89  * BOOL glass_unknowns(wimp_eventstr *e,void *handle)
90  *
91  * Use
92  *  Vets unknown events.  The important ones at the moment are
93  *  Message_DataOpen and Message_PreQuit.  Glass 1.xx supports the RISC
94  *  OS 3 prequit convention to avoid the old misunderstanding.  This may
95  *  cause problems under RISC OS 2.  If so, they'll just have to upgrade...
96  *
97  * Parameters
98  *  wimp_eventstr *e == the event in question
99  *  void *handle == 0
100  *
101  * Returns
102  *  TRUE if the event has now been processed.
103  */
104
105 static BOOL glass_unknowns(wimp_eventstr *e,void *handle)
106 {
107   BOOL handled=FALSE;
108   int filetype;
109   char *filename;
110   char buff[256];
111   os_regset r;
112   unused(handle);
113   switch (e->e)
114   {
115     case wimp_ESEND:
116     case wimp_ESENDWANTACK:
117       switch (e->data.msg.hdr.action)
118       {
119         case wimp_MDATAOPEN:
120           filetype=xferrecv_checkinsert(&filename);
121           switch (filetype)
122           {
123             case 0xfec:          /* Template file                          */
124               xferrecv_insertfileok();
125               tfile_loadFromFile(filename,xferrecv_nameToImport());
126               handled=TRUE;
127               break;
128           }
129           break;
130         case wimp_MPREQUIT:
131           if (tfile_okToQuit(TRUE))
132             intMsgs_send(glass_KILLFILES);
133           else
134           {
135             e->data.msg.hdr.your_ref=e->data.msg.hdr.my_ref;
136             wimpt_noerr(wimp_sendmessage(wimp_EACK,
137                                          &e->data.msg,
138                                          e->data.msg.hdr.task));
139           }
140           handled=TRUE;
141           break;
142         case wimp_MMODECHANGE:
143           intMsgs_send(glass_MODECHANGE);
144           break;
145         case wimp_SAVEDESK:
146           sprintf(buff,"Run %s\n",getenv("Glass$Dir"));
147           r.r[0]=2;
148           r.r[1]=e->data.msg.data.savedesk.filehandle;
149           r.r[2]=(int)buff;
150           r.r[3]=strlen(buff);
151           wimpt_noerr(os_swix(XOS_GBPB,&r));
152           handled=TRUE;
153           break;
154       }
155       break;
156   }
157   return (handled);
158 }
159
160 /*
161  * void glass_ibarHandler(ibicon i,ibicon_eventType e,void *handle)
162  *
163  * Use
164  *  Handles events for the icon bar icon (such as help requests, load and
165  *  save messages, and of course mouse clicks).
166  *
167  * Parameters
168  *  ibicon i == the handle of the icon
169  *  ibicon_eventType e == what has happened
170  *  void *handle == a dummy handle
171  */
172
173 static void glass_ibarHandler(ibicon i,ibicon_eventType e,void *handle)
174 {
175   int filetype;                  /* Filetype of a file to import           */
176   char *filename;                /* Filename of a file                     */
177   int estsize;                   /* Estimated size of a file to import     */
178   void *p;                       /* Pointer to loaded file                 */
179   unused(i);                     /* Not actually interested in the icon    */
180   unused(handle);                /* Not at all interested in the handle    */
181   switch (e)                     /* Find out what's going on               */
182   {
183     case ibicon_LEFTCLICK:       /* Clicked with select                    */
184       {
185         glass_tfile *t;
186         if (t=tfile_createTemplateFile(msgs_lookup("tfUNT")),t)
187           viewer_display(t->v);
188       }
189       break;
190     case ibicon_RIGHTCLICK:      /* Clicked with adjust                    */
191       break;                     /* Ignore it and hope it goes away        */
192     case ibicon_LOAD:            /* Load request from Filer                */
193       filetype=xferrecv_checkinsert(&filename); /* Get information         */
194       switch (filetype)
195       {
196         case 0xfec:              /* Template file                          */
197           tfile_loadFromFile(filename,xferrecv_nameToImport());
198           xferrecv_insertfileok();
199           break;
200       }
201       break;
202     case ibicon_SAVE:            /* Save from another application          */
203       filetype=xferrecv_checkimport(&estsize);  /* Get information         */
204       switch (filetype)
205       {
206         case 0xfec:              /* Template file                          */
207           if (xferrecv_returnImportedBlock(&p)!=-1)
208           {
209             tfile_loadFromMemory(&p,xferrecv_nameToImport());
210             flex_free(&p);
211             flex_compact();
212           }
213           break;
214       }
215       break;
216     case ibicon_HELP:            /* Help request                           */
217       help_startHelp();          /* Start a help reply                     */
218       help_addLine(msgs_lookup("wehIB"));
219       help_endHelp();            /* Send the message back                  */
220       break;
221   }
222 }
223
224 /*
225  * void glass_ibarMenuHandler(int hit[],void *handle)
226  *
227  * Use
228  *  Processes menu clicks for the icon bar menu.
229  *
230  * Parameters
231  *  int hit[] == array of menu hits
232  *  void *handle == 0 (dummy handle)
233  */
234
235 static void glass_ibarMenuHandler(int hit[],void *handle)
236 {
237   unused(handle);                /* This menu not attached to data struct  */
238   switch (hit[0])                /* Check which item was chosen            */
239   {
240     case glass_IBARINFO:         /* About this program                     */
241       progInfo("Glass",
242                msgs_lookup("wePUR"),
243                cright,
244                VERSION,
245                date);
246       break;
247     case glass_IBARPREFS:        /* Preferences dialogue                   */
248       gPrefs_edit();            /* Edit the preferences...                */
249       break;
250     case glass_IBARTBOX:         /* Toolbox (window manipulation)          */
251       toolbox();                 /* Handles it all...                      */
252       break;
253     case glass_IBARHEAPINFO:     /* Heap info display                      */
254       indir_heapInfo();          /* Display                                */
255       break;
256     case glass_IBARQUIT:         /* Quit program                           */
257       if (tfile_okToQuit(TRUE))  /* Check the user is sure about this      */
258         exit(0);                 /* End Glass and announce success         */
259       break;
260   }
261 }
262
263 /*
264  * void glass_ibarMenuHelp(int hit[],void *handle)
265  *
266  * Use
267  *  Help processor for icon bar menu.
268  *
269  * Parameters
270  *  int hit[] == the item to give help for
271  *  void *handle == a dummy handle
272  */
273
274 static void glass_ibarMenuHelp(int hit[],void *handle)
275 {
276   unused(handle);
277   help_startHelp();
278   help_readFromMenu("wemhIB",hit);
279   help_endHelp();
280 }
281
282 /*----- Initialisation ----------------------------------------------------*/
283
284 /*
285  * void glass_exit(void)
286  *
287  * Use
288  *  Exit handler, creates internal broadcast to close down everything.
289  */
290
291 static void glass_exit(void)
292 {
293   intMsgs_send(glass_CLOSEDOWN);
294 }
295
296 /*
297  * void glass_iconbar(void)
298  *
299  * Use
300  *  Sets up the icon bar during Glass initialisation.  Essentially, it
301  *  installs an icon bar, attaches a menu to it, and gives it a handler.
302  *  It also establishes a handler for loading and mouse clicks.
303  */
304
305 static void glass_iconbar(void)
306 {
307   ibicon i;                      /* Handle for the icon we will create     */
308   menu m;                        /* The menu to attach to the icon         */
309   m=menu_new("Glass",msgs_lookup("weIBM"));
310   i=ibicon_create(ibicon_RIGHT,"!glass",ibicon_WIMPAREA,0,0);
311   ibicon_attachMenu(i,m,glass_ibarMenuHandler,glass_ibarMenuHelp,0);
312   ibicon_eventHandler(i,glass_ibarHandler,0);
313 }
314
315 /*
316  * void glass_scanCLI(int argc,char *argv[],BOOL inited)
317  *
318  * Use
319  *  Scans command line string and loads relevant files
320  *
321  * Parameters
322  *  int argc == the number of words in the string
323  *  char *argv[] == the words, as an array of strings
324  *  BOOL inited == whether we have initialised the WIMP
325  */
326
327 static void glass_scanCLI(int argc,char *argv[],BOOL inited)
328 {
329   int i;
330   for (i=1;i<argc;i++)
331   {
332     if (utils_caselessCmp(argv[i],"-genDump")==0)
333       glass_genDump=TRUE;
334     else if (utils_caselessCmp(argv[i],"-noWindow")==0)
335       glass_noWindow=TRUE;
336     else if (utils_caselessCmp(argv[i],"-help")==0)
337     {
338       printf
339       (
340         "Glass %i.%02i (%s)\n"
341         "\n"
342         "%s"
343         "\n"
344         "Command line syntax:\n"
345         "  Glass [<option> | <filename>]...\n"
346         "\n"
347         "<filename> == file name to load\n"
348         "<option> is one of:\n"
349         "  -help == display this help\n"
350         "  -genDump == dump timings and other crap to stderr\n"
351         "  -noWindow == don't display startup window\n",
352         VERSION / 100,
353         VERSION % 100,
354         date, cright
355       );
356       exit(0);
357     }
358     else
359     {
360       if (inited)
361         tfile_loadFromFile(argv[i],argv[i]);
362     }
363   }
364 }
365
366 /*
367  * void glass_wait(int cs)
368  *
369  * Use
370  *  Makes everything stand still for a bit
371  *
372  * Parameters
373  *  in cs == number of centiseconds to wait
374  */
375
376 static void glass_wait(int cs)
377 {
378   int waiting;
379   os_regset r;
380   wimpt_noerr(os_swix(XOS_ReadMonotonicTime,&r)); /* Now wait for a bit    */
381   waiting=r.r[0];
382   while (r.r[0]-waiting<cs)      /* Half a second should do...             */
383     wimpt_noerr(os_swix(XOS_ReadMonotonicTime,&r)); /* Get the time again  */
384 }
385
386 /*
387  * void glass_initProgress(dbox d,char *message,int percent)
388  *
389  * Use
390  *  Updates the display on the loading window while we;re initialising
391  *  everything.
392  *
393  * Parameters
394  *  dbox d == the dbox being used
395  *  char *message == the message to display in the little icon.  A null
396  *    pointer indicates that the message is not to change.
397  *  int percent == the percentage complete so far
398  */
399
400 static void glass_initProgress(dbox d,char *message,int percent)
401 {
402   static dbox dd;
403   if (!dd)
404     dd=d;
405   else if (!d)
406     d=dd;
407   if (d)
408   {
409     buttons_updateSlider(d,glass_CRSLIDER,100,percent,8,FALSE);
410     dbox_setfield(d,glass_CRPERCENT,"%i",percent);
411     if (message)
412       dbox_setfield(d,glass_CRDOING,"%s",message);
413   }
414   else
415     visdelay_percent(percent);
416   if (glass_genDump)
417   {
418     fprintf(stderr,
419             "Glass init timing: %s - %i\n",
420             message ? message : "ditto",
421             clock());
422   }
423 }
424
425 /*
426  * void glass_initialise(int argc,char *argv[])
427  *
428  * Use
429  *  Does all the tedious initialisation procedure, and the bit with the
430  *  intro window.
431  *
432  * Parameters
433  *  int argc == the number of words in the CLI string
434  *  char *argv[] == the words, as an array of strings
435  */
436
437 static void glass_initialise(int argc,char *argv[])
438 {
439   sprite_area *a=0;
440   os_regset r;
441   dbox d=0;
442   wimp_redrawstr rdr;
443   BOOL more;
444
445   _dll_setname("Glass");
446
447   glass_scanCLI(argc,argv,FALSE); /* Scan command line arguments           */
448   visdelay_begin();              /* Turn on the hourglass immediately      */
449
450   /* --- Set up STEEL's options --- *
451    *
452    * We need to enable all the external module support, because we need
453    * to handle templates written to use them.  The non-WIMP shading is just
454    * a nice touch.
455    */
456
457 #ifdef glass_DEBUGGING
458   #define _options \
459     wimpt_OSCULPTRIX | \
460     wimpt_OINTERFACE | \
461     wimpt_OWIMPEXT | \
462     wimpt_ONOWIMPSHADE | \
463     wimpt_OREMSAVEICON
464 #else
465   #define _options \
466     wimpt_OSCULPTRIX | \
467     wimpt_OINTERFACE | \
468     wimpt_OWIMPEXT | \
469     wimpt_ONOWIMPSHADE | \
470     wimpt_OREMSAVEICON | \
471     wimpt_ONOBACKTRACE
472 #endif
473
474   wimpt_setOptions(_options,_options);
475
476   wimpt_init("Glass");           /* Crank up the WIMP                      */
477   res_init("Glass");             /* Point to resource files                */
478   mem_flexdInit(0, 0);        /* Initialise flex system                 */
479
480   resspr_init();                 /* Load my copious quantities of sprites  */
481   if (!glass_noWindow)
482   {
483     template_readfile(res_name("LoadTpl"));
484
485     r.r[0]=17;                   /* Need to find the size of banner sprite */
486     r.r[1]=(int)res_name("LoadSpr"); /* Set up name                        */
487     wimpt_noerr(os_swix(XOS_File,&r)); /* Do the call                      */
488     if (!flex_alloc((flex_ptr)&a,r.r[4]+4))  /* Allocate memory for sprites*/
489       a=0;                       /* If failed, don't show sprites          */
490     else
491     {
492       sprite_area_initialise(a,r.r[4]+4); /* Initialise sprite area (!)    */
493       wimpt_noerr(sprite_area_load(a,res_name("LoadSpr")));
494                                  /* Do the load as required                */
495       template_syshandle("loading")->spritearea=a; /* Rig sprite area      */
496     }
497     if (d=dbox_create("loading"),d) /* Create the dialogue box             */
498     {
499       dbox_setfield(d,
500                     glass_CRVERSION,
501                     "%i.%02i (%s)",
502                     VERSION/100,
503                     VERSION%100,
504                     date);
505       dbox_setfield(d, glass_CRGPLNOTE,
506                     "Glass is free software; it may be modified and/or "
507                     "redistributed under the terms of the GNU General "
508                     "Public License.");
509       dbox_setfield(d, glass_CRNOWARRANTY,
510                     "Glass is distributed in the hope that it will be "
511                     "useful, but WITHOUT ANY WARRANTY.");
512       dbox_display(d,dbox_STATIC_CENTRE); /* Display                       */
513       rdr.w=dbox_syshandle(d);     /* Draw the window on the screen NOW    */
514       wimpt_noerr(wimp_redraw_wind(&rdr,&more)); /* Start redraw process   */
515       while (more)                 /* Carry on till it's all done          */
516       {
517         wimpt_noerr(sculptrix_redrawWindow(&rdr)); /* Do the 3D bitties    */
518         buttons_redrawSlider(d,glass_CRSLIDER,100,0,8,FALSE);    /* Slider */
519         wimpt_noerr(wimp_get_rectangle(&rdr,&more)); /* Get the next bit   */
520       }
521     }
522     else
523       visdelay_percent(0);         /* If no box, give percentage, at least */
524
525     if (a)
526     {
527       flex_free((flex_ptr)&a);
528       flex_compact();
529     }
530   }
531   else
532     visdelay_percent(0);           /* If no box, give percentage, at least */
533
534   glass_initProgress(d,msgs_lookup("weILM:Loading messages"),0);
535   msgs_init();                   /* Read messages file (for help messages) */
536
537   glass_initProgress(d,msgs_lookup("weILW"),15);
538   template_init();
539   werr_init();                   /* Load nice error box                    */
540
541   glass_initProgress(d,msgs_lookup("weLDF"),43);
542   gSprite_init();
543   window_init();
544   tearEdit_init();
545
546   glass_iconbar();               /* Set up the icon bar appropriately      */
547
548   glass_initProgress(d,msgs_lookup("weIRP"),53);
549   gPrefs_init();
550
551   caretPtr("ptr_caret",resspr_area(),4,5); /* Enable pointer change        */
552   win_add_unknown_event_processor(glass_unknowns,0);    /* OPEN, PREQUIT   */
553   event_returnMenuHelp(TRUE);
554
555   glass_initProgress(d,msgs_lookup("weILD"),61);
556   indir_init();
557   glass_scanCLI(argc,argv,TRUE);    /* Scan command line arguments again   */
558   if (d)
559     dbox_display(d,dbox_STATIC_LASTPOS);
560   atexit(glass_exit);            /* Exit handler to free up fonts          */
561
562   if (d)
563   {
564     glass_initProgress(d,msgs_lookup("weIFI"),100);
565     glass_wait(50);
566     dbox_delete(d);
567   }
568
569   visdelay_end();                /* Finished initialisation                */
570 }
571
572 /*
573  * int main(int argc,char *argv[])
574  *
575  * Use
576  *  Control initially passed to this routine.  It essentially sets up all
577  *  initial handlers (the icon bar etc.) and lets the event system handle
578  *  the rest.
579  *
580  * Parameters
581  *  int argc == the number of command line arguments passed
582  *  char *argv == an array of command line arguments
583  *
584  * Returns
585  *  zero == successful completion
586  *  nonzero == abnormal termination
587  *
588  *  Defined return codes are:
589  */
590
591 int main(int argc,char *argv[])
592 {
593   exception_handler e;           /* Point to return to on an exception     */
594   glass_initialise(argc,argv);   /* Perform necessary initialisation       */
595   visdelay_begin();              /* Display hourglass between polls        */
596   (void)exception_registerHandler(e); /* Return here if anything goes amiss*/
597   mem_useMalloc();               /* Ensure use of standard heap            */
598   for(;;)                        /* And now, just process events until...  */
599     event_process();             /* ...kingdom come.                       */
600   return (0);                    /* Return successfully                    */
601 }