home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / utilities / m / makedrawf / !Drawf / Source / c / drawf
Encoding:
Text File  |  1997-01-15  |  22.7 KB  |  743 lines

  1. /* Wimp front end for mkdrawf and decdrawf
  2.  */
  3.  
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7.  
  8. #ifdef THROWBACK
  9. #include "dde.h"
  10. #endif
  11.  
  12. #include "load+save.h"
  13. #include "wimp.h"
  14.  
  15. #define err_base (1<<30)
  16. #define appname "Drawf"
  17. #define tem_file "<Drawf$Dir>.Templates"
  18.  
  19. /* Icons in the Options window.
  20.  */
  21. enum {
  22.   oi_mdf_frame=0,    oi_mdf_title=1,
  23.   oi_tagfile_opt=2,    oi_tagfile_icon=3,    oi_tagfile_name=4,
  24.   oi_ddf_frame=5,    oi_ddf_title=6,
  25.   oi_sprfile_opt=7,    oi_sprfile_icon=8,    oi_sprfile_name=9,
  26.   oi_jpegpfx_opt=10,    oi_jpegpfx_icon=11,    oi_jpegpfx_name=12,
  27.   oi_gen_frame=13,    oi_gen_title=14,
  28.   oi_run=15,        oi_run_always=16,
  29.   oi_units=17,        oi_units_left=18,    oi_units_right=19,
  30.   oi_units_label=20
  31. };
  32.  
  33. enum {
  34.   sv_icon=0,    sv_name=1,    sv_ok=2
  35. };
  36.  
  37. #ifdef HELPFUL
  38.  
  39. static char *opt_help[oi_units_label+1]={
  40.   "This bit of the window lets you determine how mkdrawf will behave.",
  41.   "This bit of the window lets you determine how mkdrawf will behave.",
  42.   "If this is selected, a tagfile will be opened when mkdrawf starts.",
  43.   "Drag this to a directory viewer to set the name of the tagfile.",
  44.   "The leafname, or full name, of the tagfile.",
  45.   "This bit of the window lets you determine how decdrawf will behave.",
  46.   "This bit of the window lets you determine how decdrawf will behave.",
  47.   "If this is selected, any sprites will be saved rather than inlined.",
  48.   "Drag this to a directory viewer to determine where to save sprites.",
  49.   "The leafname, or the full name, of the file in which to save sprites.",
  50.   "If this is selected, any JPEG images will be saved rather than inlined.",
  51.   "Drag this to a directory viewer to determine where to put JPEGs.",
  52.   "The prefix to which numbers will be appended for saved JPEG files.",
  53.   "This bit of the window lets you set other options.",
  54.   "This bit of the window lets you set other options.",
  55.   "If this is set, the results of running mkdrawf or decdrawf "
  56.     "will be Filer_Run, so they will be visible immediately.",
  57.   "If this is set as well as `Filer_Run output', output will be "
  58.     "Filer_Run even if mkdrawf or decdrawf produces errors.|M"
  59.     "This is not very likely to be helpful.",
  60.   "Use the arrows on either side of this to change the units decdrawf"
  61.     "will use.",
  62.   "This moves to the next smallest of the units known to decdrawf.",
  63.   "This moves to the next largest of the units known to decdrawf.",
  64.   "This bit of the window lets you determine how decdrawf will behave."
  65. };
  66.  
  67. static char *save_help[sv_ok+1]={
  68.   "Drag this to a directory viewer to save the file, "
  69.     "or to an application that can do something with it.",
  70.   "The leafname or full name to use when saving the file.",
  71.   "Click here to save the file."
  72. };
  73.  
  74. static char *menu_help[3]={
  75.   "Move the pointer right to see information about Drawf.",
  76.   "Click on this menu entry to set various options.",
  77.   "Click on this menu entry to quit Drawf."
  78. };
  79.  
  80. #endif
  81.  
  82. static int wimp_version=0;
  83.  
  84. /*------------------------------------------------------------------------*/
  85.  
  86. /* Icon block etc for icon-bar icon.
  87.  */
  88. static Icon_info baricon = {
  89.   0, { {0,0,92,68},0x7000011A,"" }
  90. };
  91.  
  92. /* Main menu.
  93.  */
  94. static mblock(3) menu = {
  95.   "Drawf",
  96.   7,2,7,0,
  97.   72,48,0,
  98.   { {0,0,0x07009021,"Info"},
  99.     {0,-1,0x07009021,"Options"},
  100.     {128,-1,0x07009021,"Quit"} }
  101. };
  102.  
  103. /* List of messages we're interested in.
  104.  */
  105. #ifdef HELPFUL
  106. static int messages[]={1,2,3,4,0x502,0};
  107. #else
  108. static int messages[]={1,2,3,4,0};
  109. #endif
  110.  
  111. /*------------------------------------------------------------------------*/
  112.  
  113. /* Error messages.
  114.  */
  115. static err_block(44)
  116.   out_of_date  = { err_base,"This application requires RISC OS 3." },
  117.   no_templates = { err_base+1,"I can't open my Templates file." },
  118.   /* Error number 2 is no longer needed */
  119.   no_window    = { err_base+3,"My Templates file is broken!" },
  120.   cw_failed    = { err_base+4,"I failed to create a window." },
  121.   ci_failed    = { err_base+5,"I failed to create an icon." },
  122.   aargh        = { err_base+6,"Something really nasty went wrong!" },
  123.   no_memory    = { err_base+7,"I've run out of memory." },
  124.   im_busy      = { err_base+8,"Sorry, but I'm busy. Try again later." },
  125.   no_errfile   = { err_base+9,"I couldn't open an error log file." },
  126.   save_failed  = { err_base+10,"Something went wrong trying to save that." },
  127.   too_long     = { err_base+11,"That command line is too long." };
  128.  
  129. /* |opting_icon| is usually 0.
  130.  * While dragging an icon from the Options window, or waiting for
  131.  * the DataSaveAck after doing so, it's the icon number of the
  132.  * icon in that window which we dragged.
  133.  */
  134. static int opting_icon=0;
  135.  
  136. /* Non-obvious fact: |output_name| contains a non-empty string
  137.  * if and only if there is an output file waiting to be saved.
  138.  * In that case, it contains the name of that file.
  139.  * Similarly for |err_name|.
  140.  */
  141. static char output_name[256]="",err_name[256]="";
  142. static long err_zero=0;    /* size of error file before prog runs */
  143.  
  144. /* We need to save the name of the input file (earlier versions
  145.  * brokenly passed around a pointer into our Wimp message block!).
  146.  * We put it in |input_name|.
  147.  */
  148. static char input_name[256]="";
  149.  
  150. /* While we're doing this sort of thing, we might as well also
  151.  * have a buffer for putting commands in.
  152.  * It might be useful for other things, too...
  153.  * The longest command we ever issue contains 5 pathnames and
  154.  * some other stuff.
  155.  * This also needs to be big enough for the window block for
  156.  * the Options window; ditto for the Save window. No trouble.
  157.  */
  158. #define scratch_size 1400
  159. static char scratch[scratch_size];
  160.  
  161. /* Another magic number of a similar sort:
  162.  * This needs to be bigger than the total size of any window (including
  163.  * indirected data).
  164.  * At the moment the Options window is getting close, so be careful.
  165.  */
  166. #define winbuf_size 2200
  167.  
  168. /* |lose(err)| reports the error, exits and dies.
  169.  * Its arg should point to an error block of some sort.
  170.  */
  171. static void lose(const void *e) {
  172.   if (wimp_version>0) {
  173.     wimp_reporterror((error_block*)e,1,appname);
  174.     wimp_closedown(); }
  175.   else
  176.     fputs(((char*)e)+4,stderr);
  177.   if (*err_name) remove(err_name);
  178.   if (*output_name) remove(output_name);
  179.   exit(0);
  180. }
  181.  
  182. /* |err(x)| reports the error, but doesn't exit.
  183.  */
  184. static void err(const void *e) {
  185.   wimp_reporterror((error_block*)e,1,appname);
  186. }
  187.  
  188. /* |finish()| exits without an error.
  189.  */
  190. static void finish(void) {
  191.   wimp_closedown();
  192.   if (*err_name) remove(err_name);
  193.   if (*output_name) remove(output_name);
  194.   exit(0);
  195. }
  196.  
  197. static void *xmalloc(int n) {
  198.   void *p=malloc(n);
  199.   if (!p) lose(&no_memory);
  200.   return p;
  201. }
  202.  
  203. /* Window and icon handles, etc.
  204.  */
  205. static int info_handle,*info_inddata;
  206. static int opt_handle,*opt_inddata;
  207. static int save_handle,*save_inddata;
  208. static int baricon_handle=-1;
  209.  
  210. /*------------------------------------------------------------------------*/
  211.  
  212. /* Various bits of state.
  213.  */
  214.  
  215. static int open_tagfile=0;
  216. static int use_spritefile=0;
  217. static int use_prefix=0;
  218. static char *tagfile_name=0;
  219. static char *spritefile_name=0;
  220. static char *jpeg_prefix=0;
  221. static char *save_ftype=0;
  222. static char *save_name=0;
  223. static char *save_title;
  224. static char *unit_string=0;
  225. static int units=2;    /* the 2 is magic */
  226.  
  227. /*------------------------------------------------------------------------*/
  228.  
  229. /* Forward-declare event handlers.
  230.  */
  231. static int do_close(int,int*);
  232. static int do_click(int,int*);
  233. static int do_dragbox(int,int*);
  234. static int do_menu(int,int*);
  235. static int do_message(int,int*);
  236.  
  237. /*------------------------------------------------------------------------*/
  238.  
  239. /* Units.
  240.  */
  241.  
  242. typedef struct { char *arg; char *name; } Unit;
  243. #define n_units 6
  244. Unit unit_list[n_units] = {
  245.   { "sp", "Scaled points" },
  246.   { "os", "OS units" },
  247.   { "pt", "Points" },
  248.   { "mm", "Millimetres" },
  249.   { "cm", "Centimetres" },
  250.   { "in", "Inches" }
  251. };
  252.  
  253. static void update_units(void) {
  254.   strcpy(unit_string,unit_list[units].name);
  255.   wimp_seticonstate(opt_handle,oi_units,0,0);
  256. }
  257.  
  258. /*------------------------------------------------------------------------*/
  259.  
  260. /* Find the template for window |name|, put its indirected data ptr at |inddata|
  261.  * and return the window handle.
  262.  */
  263. static int create_window(const char *name, void *space, int **inddata) {
  264.   int handle,tsize,isize;
  265.   if (wimp_xtemplate(name,&tsize,&isize,0,0)<0) lose(&no_window);
  266.   if (tsize>winbuf_size) lose(&cw_failed);
  267.   *inddata=xmalloc(isize);
  268.   if (wimp_loadtemplate(name,space,*inddata,isize,(char*)-1,0,0)<0)
  269.     lose(&no_window);
  270.   if ((handle=wimp_createwindow(space))<0) lose(&cw_failed);
  271.   return handle;
  272. }
  273.  
  274. /* Turn a control-terminated string into a null-terminated one.
  275.  */
  276. void sanitise(char *s) {
  277.   char c;
  278.   while ((c=*s++)>=32) ;
  279.   s[-1]=0;
  280. }
  281.  
  282. /* Do all the usual Wimp initialisation things: create windows and icons
  283.  * and menus, and so on.
  284.  * Exit in an appropriate way if something goes wrong.
  285.  */
  286. static void init_wimp(void) {
  287.   /* Become a Wimp task. */
  288.   void *space=xmalloc(winbuf_size);
  289.   wimp_version=wimp_initialise(310,"Drawf",messages);
  290.   if (wimp_version<0) lose(&aargh);
  291.   if (wimp_version<310) lose(&out_of_date);
  292.   /* Create windows. */
  293.   if (wimp_opentemplate(tem_file)) lose(&no_templates);
  294.   info_handle=create_window("Info",space,&info_inddata);
  295.   opt_handle=create_window("Options",space,&opt_inddata);
  296.   save_handle=create_window("Save",space,&save_inddata);
  297.   save_title=((char**)space)[18]+5; /* actually points to "decdrawf output" */
  298.   free(space);
  299.   /* Fill in menu. */
  300.   menu.items[0].leads_to.window=info_handle;
  301.   /* Bits of writable data. */
  302.   { Icon_block *i;
  303.     i=wimp_geticonstate(opt_handle,oi_tagfile_name);
  304.     tagfile_name=i->data.indtext.text;
  305.     sanitise(tagfile_name);
  306.     i=wimp_geticonstate(opt_handle,oi_sprfile_name);
  307.     spritefile_name=i->data.indtext.text;
  308.     sanitise(spritefile_name);
  309.     i=wimp_geticonstate(opt_handle,oi_jpegpfx_name);
  310.     jpeg_prefix=i->data.indtext.text;
  311.     sanitise(jpeg_prefix);
  312.     i=wimp_geticonstate(save_handle,sv_icon);
  313.     save_ftype=i->data.indsprite.name+5;    /* points to "fff" or "aff" */
  314.     sanitise(save_ftype);
  315.     i=wimp_geticonstate(save_handle,sv_name);
  316.     save_name=i->data.indtext.text;
  317.     sanitise(save_name);
  318.     i=wimp_geticonstate(opt_handle,oi_units);
  319.     unit_string=i->data.indtext.text;
  320.     strcpy(unit_string,unit_list[units].name);
  321.   }
  322.   /* Close the template file, before we forget. */
  323.   wimp_closetemplate();
  324.   /* Create iconbar icon. */
  325.   baricon.window=-7;
  326.   baricon.block.data.indsprite.name="!drawf";
  327.   baricon.block.data.indsprite.area=(int*)1;
  328.   baricon.block.data.indsprite.length=6;
  329.   if ((baricon_handle=wimp_createicon(0,&baricon))<0) lose(&ci_failed);
  330.   /* Set up event handlers. */
  331.   wimpfns[reason_close]=do_close;
  332.   wimpfns[reason_click]=do_click;
  333.   wimpfns[reason_dragbox]=do_dragbox;
  334.   wimpfns[reason_menu]=do_menu;
  335.   wimpfns[reason_message]=
  336.    wimpfns[reason_message_rec]=
  337.    wimpfns[reason_message_ack]=do_message;
  338.   /* We're done. */
  339. }
  340.  
  341. /*------------------------------------------------------------------------*/
  342.  
  343. /* Shade or unshade icons n+1,n+2 in the options window
  344.  * according to the selection state of icon n. Also toggle
  345.  * that state; it's the *new* state that matters.
  346.  * Returns 1<<21 for selected, else 0.
  347.  */
  348. static int maybe_shade(int n) {
  349.   int t = wimp_geticonstate(opt_handle,n)->flags.val;
  350.   int u = (t&=(1<<21))<<1;
  351.   wimp_seticonstate(opt_handle,n,1<<21,0);
  352.   wimp_seticonstate(opt_handle,n+1,u,1<<22);
  353.   wimp_seticonstate(opt_handle,n+2,u,1<<22);
  354.   return t^(1<<21);
  355. }
  356.  
  357. /* Leafname from pathname.
  358.  */
  359. static const char *leaf(const char *s) {
  360.   const char *t=s;
  361.   char c;
  362.   while ((c=*t++)!=0)
  363.     if (c=='.'||c==':') s=t;
  364.   return s;
  365. }
  366.  
  367. /* Leafname, or empty string if no path.
  368.  */
  369. static const char *leaf0(const char *s) {
  370.   const char *t=leaf(s);
  371.   return t==s ? (const char *)"" : t;    /* (const char *)"" ... ludicrous */
  372. }
  373.  
  374. /* Leafname of a name in indirected text of icon n in window w.
  375.  */
  376. #define leafname(w,n) leaf(wimp_geticonstate((w),(n))->data.indtext.text)
  377.  
  378. /*------------------------------------------------------------------------*/
  379.  
  380. #ifdef THROWBACK
  381. static int using_dde=0;
  382. #endif
  383.  
  384. /* When we start a task, we must make sure the command line is
  385.  * no longer than 256c; otherwise something barfs in a big way
  386.  * and crashes the machine irrevocably (well, it does with my
  387.  * machine anyway).
  388.  */
  389. static int start_task(char *s) {
  390.   int l=strlen(s);
  391.   if (l<256) return wimp_starttask(s);
  392. #ifdef THROWBACK
  393.   if (using_dde) return dde_starttask(l,s);
  394.   else
  395. #endif
  396.   err(&too_long); return -1;
  397. }
  398.  
  399. /* Create the error file.
  400.  */
  401. static void create_errors(const char *prog) {
  402.   FILE *f=fopen(err_name,"w");
  403.   if (!f) { err(&no_errfile); *err_name=0; return; }
  404. #ifdef THROWBACK
  405.   using_dde=dde_exists();
  406. #endif
  407.   fprintf(f,"Errors and warnings from %s:\n"
  408.             "Input file: %s\n"
  409.             "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
  410.             "~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n",
  411.            prog,input_name);
  412.   err_zero=ftell(f);
  413.   fclose(f);
  414. }
  415.  
  416. #ifdef THROWBACK
  417.  
  418. /* If we have the DDE available, we can do throwback:
  419.  * go through the file and send the relevant info to
  420.  * the DDEUtils SWIs.
  421.  */
  422. static void do_throwback(void) {
  423.   FILE *f=fopen(err_name,"r");
  424.   unsigned int l; char *cp;
  425.   throwback_start();
  426.   throwback_filename(input_name);
  427.   while (fgets(scratch,256,f)) {
  428.     sanitise(scratch);
  429.     if (strncmp(scratch,"Line ",5)) continue;
  430.     l=(unsigned int)strtoul(scratch+5,&cp,10);
  431.     if (*cp==':' && cp[1]==' ' && (l || (cp!=scratch+5))) {
  432.       /* Looks like a real error message. Assume it is. */
  433.       int ty;
  434.       if (cp[2]=='w') { ty=0; cp+=11; }
  435.       else if (cp[2]=='e') { ty=1; cp+=9; }
  436.       else if (cp[2]=='f') { ty=2; cp+=15; }
  437.       else ty=2;    /* this shouldn't happen */
  438.       throwback_error(input_name,l,ty,cp);
  439.     }
  440.   }
  441.   throwback_end();
  442.   fclose(f);
  443. }
  444.  
  445. #endif
  446.  
  447. /* Actually save the file. To be more precise: copy it to the
  448.  * right place.
  449.  * Return 0 for failure, 1 for success.
  450.  */
  451. static int do_really_save(void) {
  452.   /* copy from to ~CDF~V */
  453.   sprintf(scratch,"Copy %s %s ~CDF~V",output_name,save_name);
  454.   system(scratch);
  455.   *output_name=0;
  456.   wimp_closewindow(&save_handle);
  457.   return 1;
  458. }
  459.  
  460. /* Do the first things needed for a launch.
  461.  */
  462. static void begin_launch(void) {
  463.   strcpy(save_name,leaf0(input_name));
  464.   if (*output_name) remove(output_name);
  465.   if (*err_name) remove(err_name);
  466.   tmpnam(output_name);
  467.   tmpnam(err_name);
  468.   hourglass_start(50);
  469. }
  470.  
  471. /* And the last.
  472.  */
  473. static void finish_launch(char c) {
  474.   /* Run mkdrawf or decdrawf. */
  475.   int no_err=1<<21;
  476.   start_task(scratch);
  477.   hourglass_off();
  478.   /* Get the error file opened by a text editor, or else send its contents
  479.    * to whatever's doing throwback. But don't do any of this if there weren't
  480.    * any diagnostics.
  481.    * We don't delete the error file at this point, because the Filer_Run
  482.    * won't take place instantaneously. It's deleted next time we need to
  483.    * use an error file...
  484.    */
  485.   if (*err_name) {
  486.     if (file_size(err_name)!=err_zero) {
  487.       no_err=0;
  488. #ifdef THROWBACK
  489.       if (using_dde && c=='a') {
  490.         do_throwback();
  491.         remove(err_name);
  492.         *err_name=0; }
  493.       else {
  494. #endif
  495.         sprintf(scratch,"Filer_Run %s",err_name);
  496.         system(scratch);
  497. #ifdef THROWBACK
  498.       }
  499. #endif
  500.     } else { remove(err_name); *err_name=0; }
  501.   }
  502.   /* If appropriate, Filer_Run the output file. */
  503.   if (wimp_geticonstate(opt_handle,oi_run_always)->flags.val&(1<<21)
  504.       || wimp_geticonstate(opt_handle,oi_run)->flags.val&no_err) {
  505.     sprintf(scratch,"Filer_Run %s",output_name);
  506.     system(scratch);
  507.   }
  508.   /* Now open the Save window. */
  509.   strcpy(save_title,c=='a'?"mkdrawf output":"decdrawf output");
  510.   *save_ftype=c;
  511.   { int *block=(int*)scratch;
  512.     block[0]=save_handle;
  513.     wimp_getwindowinfo(block);
  514.     wimp_openwindow(block);
  515.   }
  516. }
  517.  
  518. /* Launch mkdrawf. |name| is the name of the input file.
  519.  */
  520. static void launch_mkdrawf(const char *name) {
  521.   strcpy(input_name,name);
  522.   begin_launch();
  523.   create_errors("mkdrawf");
  524.   /* mkdrawf input output 2>>errs -t tags */
  525.   sprintf(scratch,"mkdrawf -e %s %s %s%s%s%s",
  526.           input_name,output_name,
  527.           *err_name?"2>>":"",err_name,
  528.           open_tagfile?" -t ":"",open_tagfile?tagfile_name:"");
  529.   finish_launch('a');
  530. }
  531.  
  532. static void launch_decdrawf(const char *name) {
  533.   strcpy(input_name,name);
  534.   begin_launch();
  535.   create_errors("decdrawf");
  536.   /* decdrawf input >output 2>>errs -s sprites -j jpeg */
  537.   sprintf(scratch,"decdrawf -e %s >%s %s%s%s%s%s%s%s%s",
  538.           input_name,output_name,
  539.           *err_name?"2>>":"",err_name,
  540.           use_spritefile?" -s ":"",use_spritefile?spritefile_name:"",
  541.           use_prefix?" -j ":"",use_prefix?jpeg_prefix:"",
  542.           units!=2?" -u ":"",units!=2?unit_list[units].arg:"");
  543.   finish_launch('f');
  544. }
  545.  
  546. /*------------------------------------------------------------------------*/
  547.  
  548. /* Event handlers.
  549.  */
  550.  
  551. static int do_close(int reason, int *block) {
  552.   reason=reason;
  553.   if (block[0]==save_handle) {
  554.     if (*output_name) { remove(output_name); *output_name=0; }
  555.     if (*err_name) { remove(err_name); *err_name=0; }
  556.   }
  557.   wimp_closewindow(block);
  558.   return 0;
  559. }
  560.  
  561. static int do_click(int reason, int *block) {
  562.   int but=block[2], win=block[3], icn=block[4];
  563.   reason=reason;
  564.   /* block[2..4]: buttons, window, icon */
  565.   if (win==-2 && icn==baricon_handle && but==2)
  566.     wimp_createmenu((Menu_block*)&menu,block[0]-64,240);
  567.   if (but==2) return 0;    /* ignore Menu clicks */
  568.   if (win==save_handle) {
  569.     if (icn==sv_icon && but==64) {
  570.       if (opting_icon) err(&im_busy);
  571.       else begin_drag(save_handle,wimp_geticonstate(save_handle,icn));
  572.     }
  573.     else if (icn==sv_ok && but==4)
  574.       do_really_save();
  575.     return 0;
  576.   }
  577.   if (win!=opt_handle) return 0;
  578.   /* We now know it's in the options window. Which {ic|butt}on? */
  579.   if (but==4 || but==1) {
  580.     if (but==1) {
  581.       /* Adjust-clicking on units arrows goes the other way.
  582.        * (Adjust-clicking elsewhere does the same as Select-clicking.)
  583.        */
  584.       if (icn==oi_units_left) icn=oi_units_right;
  585.       else if (icn==oi_units_right) icn=oi_units_left;
  586.     }
  587.     switch(icn) {
  588.       case oi_tagfile_opt: open_tagfile=maybe_shade(oi_tagfile_opt); break;
  589.       case oi_sprfile_opt: use_spritefile=maybe_shade(oi_sprfile_opt); break;
  590.       case oi_jpegpfx_opt: use_prefix=maybe_shade(oi_jpegpfx_opt); break;
  591.       case oi_units_left: if (units>0) { --units; update_units(); } break;
  592.       case oi_units_right: if (units<n_units-1) { ++units; update_units(); } break;
  593.     }
  594.     return 0;
  595.   }
  596.   if (but!=64) return 0;    /* not drag */
  597.   if (icn!=oi_tagfile_icon &&    /* must be one of the file icons */
  598.       icn!=oi_sprfile_icon &&
  599.       icn!=oi_jpegpfx_icon) return 0;
  600.   if (opting_icon) { err(&im_busy); return 0; }
  601.   begin_drag(opt_handle,wimp_geticonstate(opt_handle,icn));
  602.   opting_icon=icn;
  603.   return 0;
  604. }
  605.  
  606. static int do_dragbox(int reason, int *block) {
  607.   reason=reason;
  608.   wimp_getpointerinfo(block+2);
  609.   if (block[5]==opt_handle) { opting_icon=0; return 0; }
  610.   block[7]=block[2];    /* x */
  611.   block[8]=block[3];    /* y */
  612.   block[3]=0;    /* your_ref: original message */
  613.   block[4]=1;    /* Message_DataSave */
  614.       /* block[5..8] filled in already */
  615.   block[9]=0;    /* estimated size in bytes */
  616.   block[10]=(*save_ftype=='a')?0xAFF:0xFFF;
  617.   strcpy((char*)(block+11),
  618.     opting_icon ? leafname(opt_handle,opting_icon+1)
  619.                 : leaf(save_name));
  620.   block[0]=(strlen((char*)(block+11))+48)&~3;
  621.   wimp_sendmessage4(reason_message_rec,block,block[5],block[6]);
  622.                   /* window handle serves as taskID */
  623.   return 0;
  624. }
  625.  
  626. static int do_menu(int reason, int *block) {
  627.   reason=reason;
  628.   if (block[0]==1) {
  629.     /* Open Options window. */
  630.     int *b=(int*)scratch;
  631.     b[0]=opt_handle;
  632.     wimp_getwindowinfo(b);
  633.     wimp_openwindow(b); }
  634.   else if (block[0]==2) finish();
  635.   return 0;
  636. }
  637.  
  638. static int do_message(int reason, int *block) {
  639.   reason=reason;
  640.   switch(block[4]) {
  641.     case 0:    /* Message_Quit */
  642.       finish();
  643.     case 1:    /* Message_DataSave */
  644.       if (reason==19 && block[1]==task_handle) {
  645.         /* Returned to sender ... */
  646.         opting_icon=0;
  647.         return 0; }
  648.       if (block[5]!=-2 || *output_name) return 0;
  649.       block[0]=60;        /* size of block */
  650.       block[3]=block[2];    /* your_ref */
  651.       block[4]=2;        /* DataSaveAck */
  652.       block[9]=-1;        /* not safe */
  653.       strcpy((char*)(block+11),"<Wimp$Scrap>");
  654.       wimp_sendmessage(reason_message,block,block[1]);
  655.       break;
  656.     case 2:    /* Message_DataSaveAck */
  657.       if (opting_icon) {
  658.         char *z;
  659.         if (block[1]==task_handle) {
  660.           opting_icon=0; return 0; }
  661.         switch(opting_icon) {
  662.           case oi_tagfile_icon: z=tagfile_name; break;
  663.           case oi_sprfile_icon: z=spritefile_name; break;
  664.           case oi_jpegpfx_icon: z=jpeg_prefix; break;
  665.           default: return 0; /* shouldn't happen */
  666.         }
  667.         strcpy(z,(char*)(block+11));
  668.         wimp_seticonstate(opt_handle,opting_icon+1,0,0);
  669.         opting_icon=0; return 0;
  670.         /* *Don't* send DataLoad: we haven't saved anything! */
  671.       } else {
  672.         strcpy(save_name,(char*)(block+11));
  673.         wimp_seticonstate(save_handle,sv_name,0,0);
  674.         do_really_save();
  675.         block[3]=block[2];    /* your_ref */
  676.         block[4]=3;        /* DataLoad */
  677.         wimp_sendmessage(reason_message_rec,block,block[1]);
  678.       }
  679.       break;
  680.     case 3:    /* Message_DataLoad */
  681.       if (reason==19 && block[1]==task_handle) {
  682.         /* Returned to sender ... */
  683.         err(&save_failed);
  684.         return 0;
  685.       }
  686.       if (block[5]!=-2) return 0;    /* not iconbar icon */
  687. #if 0
  688.       if (block[1]==task_handle && saving) {
  689.         remove(output_name); *output_name=0; busy=0; saving=0;
  690.         err(&save_failed); return 0; }
  691. #endif
  692.       switch(block[10]) {
  693.         case 0xFFF: case 0xFE4:
  694.           launch_mkdrawf((char*)(block+11)); break;
  695.         case 0xAFF: launch_decdrawf((char*)(block+11)); break;
  696.         default: return 0;    /* don't know how to deal with that... */
  697.       }
  698.       /* Better be polite and acknowledge the message */
  699.       block[3]=block[2];    /* your_ref */
  700.       block[4]=4;        /* DataLoadAck */
  701.       wimp_sendmessage(reason_message,block,block[1]);
  702.       break;
  703.     case 4:    /* Message_DataLoadAck */
  704.       break;
  705. #ifdef HELPFUL
  706.     case 0x502: {
  707.       int win=block[8],icn=block[9],l;
  708.       char *msg=0;
  709.       if (win==-2) msg="This is the Drawf icon.|M"
  710.                        "Drag a text file to it to make it into a drawfile using mkdrawf.|M"
  711.                        "Drag a drawfile to it to decode it using decdrawf.";
  712.       else if (win==opt_handle) {
  713.         if ((unsigned)icn<=oi_run_always) msg=opt_help[icn]; }
  714.       else if (win==save_handle) {
  715.         if ((unsigned)icn<=sv_ok) msg=save_help[icn]; }
  716.       else if (win==(int)&menu) msg=menu_help[icn];
  717.       else {
  718.         int b[3];
  719.         wimp_getmenustate0(b);
  720.         if ((unsigned)b[0]<3) msg=menu_help[b[0]];
  721.       }
  722.       if (msg) {
  723.         block[3]=block[2];
  724.         block[4]=0x503;
  725.         l=strlen(msg);
  726.         memcpy((char*)(block+5),msg,l+1);
  727.         block[0]=(l+24)&~3;
  728.         wimp_sendmessage(reason_message,block,block[1]); }
  729.     }
  730. #endif
  731.   }
  732.   return 0;
  733. }
  734.  
  735. int main(void) {
  736.   init_wimp();
  737.   while (1)
  738.     wimp_poll(mask_null|mask_ptr_leaving|mask_ptr_entering|
  739.               mask_losecaret|mask_gaincaret);
  740.   /* Not reached: */
  741.   return 0;
  742. }
  743.