1 /* Title: -> c.xfersend
2 * Purpose: generalised data transfer to a concurrent wimp program.
5 /*----- Licensing note ----------------------------------------------------*
7 * This file is part of Straylight's Steel library.
9 * Steel is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
14 * Steel is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with Steel. If not, write to the Free Software Foundation,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
47 static int rcvbufsize ;
48 static int xfersend__msgid;
49 static xfersend_saveproc xfersend__saveproc;
50 static xfersend_sendproc xfersend__sendproc;
51 static xfersend_printproc xfersend__printproc;
52 static int xfersend__filetype;
53 static void *xfersend__savehandle;
54 static int xfersend__estsize;
55 static wimp_t xfersend__receiver ;
56 static BOOL xfersend__fileissafe ;
57 static char xfersend__filename[256];
59 static wimp_mousestr xfersend__mousestr;
60 static wimp_msgstr xfersend__msg;
61 static BOOL xfersend__close;
62 static wimp_w xfersend__w;
63 static wimp_i xfersend__i;
65 static BOOL xfersend__finishedXfer;
67 static void xfersend__iconDel(wimp_w w,wimp_i i,BOOL del)
69 if (wimpt_options() & wimpt_OREMSAVEICON)
72 wimp_set_icon_state(w,i,(1<<23)+(1<<7),(1<<23)+(1<<7));
74 wimp_set_icon_state(w,i,0,(1<<23)+(1<<7));
78 void xfersend_close_on_xfer(BOOL do_we_close, wimp_w w)
80 xfersend__close = do_we_close;
84 static void xfersend__winclose(void)
88 wimpt_noerr(wimp_sendwmessage(wimp_ECLOSE, (wimp_msgstr*) &e, e.o.w, -1));
92 static BOOL xfersend__unknowns(wimp_eventstr *e, void *handle) {
94 tracef1("xfersend raw event %i.\n", e->e);
97 tracef0("drag event received.\n");
99 wimp_get_point_info(&xfersend__mousestr);
100 if (xfersend__mousestr.w == -1) {
101 tracef0("drag to no window: has no effect.\n");
102 xfersend__finishedXfer=TRUE;
107 tracef1("drag to window %i: offer data.\n", xfersend__mousestr.w);
108 /* msg.hdr.size = sizeof(wimp_msghdr) + sizeof(wimp_msgdatasave); */
109 msg.hdr.task = xfersend__mousestr.w;
110 msg.hdr.your_ref = 0;
111 msg.hdr.action = wimp_MDATASAVE;
112 msg.data.datasave.w = xfersend__mousestr.w;
113 msg.data.datasave.i = xfersend__mousestr.i;
114 msg.data.datasave.x = xfersend__mousestr.x;
115 msg.data.datasave.y = xfersend__mousestr.y;
116 msg.data.datasave.type = xfersend__filetype;
117 msg.data.datasave.estsize = xfersend__estsize;
121 strncpy(name,xfersend__filename, 256);
122 tail = strlen(name); /* point at the zero */
123 while (tail > 0 && name[tail-1] != '.' && name[tail-1] != ':')
126 strncpy(msg.data.datasave.leaf, name + tail, 210);
127 msg.data.dataload.name[211] = 0; /* Avoid boundcheck warning */
128 msg.hdr.size = (48+strlen(msg.data.datasave.leaf)) & ~3;
129 tracef1("suggest leaf '%s'.\n", (int) &msg.data.datasave.leaf[0]);
131 wimpt_noerr(wimp_sendwmessage(
132 wimp_ESENDWANTACK, &msg, xfersend__mousestr.w, xfersend__mousestr.i));
133 xfersend__msgid = msg.hdr.my_ref; /* filled in by wimp. */
134 /* We still get unknown events, so we'll get the reply sometime. */
140 case wimp_ESENDWANTACK:
143 tracef("xfersend msg %x received: %i %i.\n",
144 e->data.msg.hdr.action,e->data.msg.hdr.your_ref,xfersend__msgid);
147 if (e->data.msg.hdr.your_ref == xfersend__msgid)
148 switch (e->data.msg.hdr.action)
151 if (xfersend__sendproc != 0)
153 xfersend__fileissafe = FALSE ;
155 /* He wants to do an in-core transfer, and we can do this. */
156 /* Note that this can't be other than the first response, as others
157 are grabbed by sendbuf */
159 tracef0("ram transfer starting.\n");
161 /* Prepare the reply record. */
162 xfersend__msg = e->data.msg;
163 xfersend__msg.hdr.your_ref = xfersend__msg.hdr.my_ref;
164 xfersend__msg.hdr.action = wimp_MRAMTRANSMIT;
165 xfersend__msg.data.ramtransmit.addr = e->data.msg.data.ramfetch.addr;
166 xfersend__msg.data.ramtransmit.nbyteswritten = 0; /* so far. */
167 rcvbufsize = e->data.msg.data.ramfetch.nbytes;
169 xfersend__receiver = e->data.msg.hdr.task ;
170 /* the copy in xfersend__msg.hdr.task is overwritten by the Wimp
173 if (xfersend__sendproc(xfersend__savehandle, &rcvbufsize))
175 /* See sendbuf for all the real work for this case... */
176 tracef0("The send succeeded; send final RAMTRANSMIT.\n");
178 /* We may have transferred some data but not yet told the
179 other end about it. xfersend__msg contains a final RAMTRANSMIT,
180 which does not quite fill his buffer (or we'd have sent it already)
181 thus signalling to him that the transfer is over. */
183 wimpt_noerr(wimp_sendmessage(
186 xfersend__receiver));
187 xfersend__finishedXfer=TRUE;
188 if(xfersend__close) xfersend__winclose();
189 else xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
193 tracef0("the send failed.\n");
194 xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
195 xfersend__finishedXfer=TRUE;
201 if (getenv("Wimp$Scrap")==0)
202 xfersend__finishedXfer=TRUE;
203 /*** The other application reports an error, and I don't get my ***
204 *** no-acknowledgement message to tell me to abort the data ***
209 case wimp_MPrintFile: /* was dropped on a printer application */
210 if (xfersend__printproc != 0)
214 tracef0("print request acceptable\n");
215 xfersend__fileissafe = FALSE ;
217 res = xfersend__printproc(&e->data.msg.data.print.name[0],
218 xfersend__savehandle) ;
220 xfersend__msg = e->data.msg;
221 xfersend__msg.hdr.your_ref = xfersend__msg.hdr.my_ref;
222 xfersend__msg.hdr.action =
223 res >= 0 ? wimp_MDATALOAD : wimp_MWillPrint;
224 xfersend__msg.data.print.type = res ; /* in case it's been saved */
225 wimpt_noerr(wimp_sendmessage(
228 xfersend__receiver));
229 xfersend__msgid=xfersend__msg.hdr.my_ref;
230 if (res==xfersend_printPrinted)
232 xfersend__finishedXfer=TRUE;
233 if(xfersend__close) xfersend__winclose();
234 else xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
236 else if (res==xfersend_printFailed)
237 xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
242 case wimp_MDATALOADOK:
243 xfersend__finishedXfer=TRUE;
244 if(xfersend__close) xfersend__winclose();
245 else xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
249 case wimp_MDATASAVEOK:
251 tracef4("datasaveok %i %i %i %i.\n",
252 e->data.msg.hdr.size,
253 e->data.msg.hdr.task,
254 e->data.msg.hdr.your_ref,
255 e->data.msg.hdr.my_ref);
256 tracef4("datasaveok %x %x %x %x.\n",
257 e->data.msg.data.words[0],
258 e->data.msg.data.words[1],
259 e->data.msg.data.words[2],
260 e->data.msg.data.words[3]);
261 tracef1("it's the datasaveok, to file '%s'.\n",
262 (int) &e->data.msg.data.datasaveok.name[0]);
264 tracef1("save to filename '%s'.\n",
265 (int) &e->data.msg.data.datasaveok.name[0]);
267 xfersend__fileissafe = e->data.msg.data.datasaveok.estsize >= 0 ;
269 if (xfersend__saveproc(&e->data.msg.data.datasaveok.name[0],
270 xfersend__savehandle))
272 tracef0("the save succeeded: send dataload\n");
274 xfersend__msg = e->data.msg;
275 /* sets hdr.size, data.w,i,x,y, size, name */
276 xfersend__msg.hdr.your_ref = e->data.msg.hdr.my_ref;
277 xfersend__msg.hdr.action = wimp_MDATALOAD;
278 xfersend__msg.data.dataload.type = xfersend__filetype ;
279 wimpt_noerr(wimp_sendmessage(
282 e->data.msg.hdr.task));
283 xfersend__msgid=xfersend__msg.hdr.my_ref;
287 /* he has already reported the error: nothing more to do. */
288 tracef0("save was not successful.\n");
289 xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
290 xfersend__finishedXfer=TRUE;
295 return FALSE ; /* unknown not dealt with */
298 if (e->data.msg.hdr.my_ref == xfersend__msgid)
300 switch (e->data.msg.hdr.action)
304 /* It looks as if he hasn't acknowledged my DATALOAD acknowledge:
305 thus it may be a loose scrap file, and must be deleted. */
307 tracef0("he hasn't ack'd our data load of temp file, so delete the file.\n");
308 werr(FALSE, msgs_lookup("xfersend1:Bad data transfer, receiver dead."));
309 sprintf(a, "%%delete %s", &xfersend__msg.data.dataload.name[0]);
311 xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
312 xfersend__finishedXfer=TRUE;
316 xfersend__finishedXfer=TRUE;
317 xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
328 static int sendbuf__state ;
330 static BOOL sendbuf__unknowns(wimp_eventstr *e, void *h)
334 tracef4("sendbuf__unknowns %d %d %d %d\n",
335 e->data.msg.hdr.my_ref, e->data.msg.hdr.your_ref,
336 xfersend__msg.hdr.your_ref, xfersend__msg.hdr.my_ref) ;
338 if ((e->e == wimp_ESENDWANTACK || e->e == wimp_ESEND) &&
339 e->data.msg.hdr.your_ref == xfersend__msg.hdr.my_ref &&
340 e->data.msg.hdr.action == wimp_MRAMFETCH)
342 /* Prepare xfersend__msg as the next RAMTRANSMIT. Most of
343 the fields are already set up. */
345 xfersend__msg.data.ramtransmit.addr = e->data.msg.data.ramfetch.addr;
346 xfersend__msg.data.ramtransmit.nbyteswritten = 0;
347 xfersend__msg.hdr.your_ref = e->data.msg.hdr.my_ref ;
348 rcvbufsize = e->data.msg.data.ramfetch.nbytes;
350 tracef2("RAMFETCH received: continue with buffer at %x, size %d\n",
351 (int) xfersend__msg.data.ramtransmit.addr, rcvbufsize) ;
354 return TRUE ; /* We've had another RAMFETCH: off we go again */
357 if (e->e == wimp_EACK &&
358 e->data.msg.hdr.my_ref == xfersend__msg.hdr.my_ref)
361 tracef0("xfersend RAMTRANSMIT bounced; set failed state\n") ;
362 return TRUE ;/* our message bounced back; give up */
365 return FALSE ; /* we don't want it */
369 BOOL xfersend_sendbuf(char *buffer, int size)
372 /* Called by his sendproc when sending things in memory. The
373 reply record is in xfersend__msg. */
375 tracef2("xfersend_sendbuf %i %i\n", (int) buffer, size);
377 /* Make the data transfer */
378 tracef3("transfer block of %d from %x to %x\n", size, (int) buffer,
379 (int) (xfersend__msg.data.ramtransmit.addr +
380 xfersend__msg.data.ramtransmit.nbyteswritten)) ;
382 wimpt_noerr(wimp_transferblock(
386 xfersend__msg.data.ramtransmit.addr +
387 xfersend__msg.data.ramtransmit.nbyteswritten,
390 /* record bytes to be sent to the other end */
391 xfersend__msg.data.ramtransmit.nbyteswritten += size;
394 /* if size != 0, there are still bytes to send. */
396 if (rcvbufsize > 0) return TRUE;
398 tracef1("xfersend message has put %d into buffer\n",size) ;
399 /* Tell him that you've done it */
400 wimpt_noerr(wimp_sendmessage(
403 xfersend__receiver));
405 /* Get his reply. Poll and despatch events until get nack or message */
409 win_add_unknown_event_processor(sendbuf__unknowns, 0) ;
410 do { event_process() ; } while (sendbuf__state == 0) ;
411 win_remove_unknown_event_processor(sendbuf__unknowns, 0) ;
413 /* This exit happens in the cases where the buffers at each end
414 are of identical size. So, return for another call to sendbuf, or
415 so that the sendbuf procedure can return. */
417 return sendbuf__state != 2 ; /* OK unless state = broken */
420 BOOL xfersend(int filetype, char *filename, int estsize,
421 xfersend_saveproc saver,
422 xfersend_sendproc sender,
423 xfersend_printproc printer,
424 wimp_eventstr *e, void *handle)
429 wimp_w w = e->data.but.m.w;
431 xfersend__saveproc = saver;
432 xfersend__sendproc = sender;
433 xfersend__printproc = printer;
434 xfersend__filetype = filetype;
435 xfersend__estsize = estsize;
436 xfersend__savehandle = handle;
438 strcpy(xfersend__filename, msgs_lookup("xfersend2:Selection"));
440 strncpy(xfersend__filename,filename,256);
443 xfersend__w = e->data.but.m.w;
444 xfersend__i = e->data.but.m.i;
445 tracef0("Initiate a drag.\n");
446 r.r[0]=161; /* Read CMOS */
447 r.r[1]=0x1c; /* Support DragASrite? */
448 wimpt_noerr(os_swix(XOS_Byte,&r));
449 wimp_get_wind_state(w, &wstate);
450 wimp_get_icon_info(w, e->data.but.m.i, &icon);
451 dr.box.x0 = wstate.o.box.x0 - wstate.o.x + icon.box.x0;
452 dr.box.y0 = wstate.o.box.y1 - wstate.o.y + icon.box.y0;
453 dr.box.x1 = wstate.o.box.x0 - wstate.o.x + icon.box.x1;
454 dr.box.y1 = wstate.o.box.y1 - wstate.o.y + icon.box.y1;
455 if ((r.r[2] & 2) && wimpt_getVersion()>=300)
457 r.r[0]=0xC5; /* Centre, whole-screen, drop-shadow */
459 r.r[2]=(int)fileicon_spriteName(filetype,filename);
461 xfersend__iconDel(xfersend__w,xfersend__i,TRUE);
462 wimpt_noerr(os_swix(XDragASprite_Start,&r));
466 /* Pedestrian drag-box */
467 dr.window = w; /* not relevant. */
468 dr.type = wimp_USER_FIXED;
471 dr.parent.x1 = wimpt_scwidth();
472 dr.parent.y1 = wimpt_scheight();
476 win_add_unknown_event_processor(xfersend__unknowns, 0);
477 xfersend__finishedXfer=FALSE;
478 while (xfersend__finishedXfer==FALSE)
480 win_remove_unknown_event_processor(xfersend__unknowns, 0);
486 BOOL xfersend_file_is_safe()
488 return xfersend__fileissafe ;
491 void xfersend_set_fileissafe(BOOL value)
493 xfersend__fileissafe = value;
497 * BOOL xfersend_sendBlock(void *block,size_t length,int *maxbuf)
500 * Sends a block to xfersend_sendbuf() a chunk at a time.
503 * void *block == pointer to the block
504 * size_t length == length of block
505 * int *maxbuf == pointer to the length of the destination task's buffer
508 * TRUE if successful, FALSE if it failed. If this returns FALSE, you must
509 * return FALSE immediately.
512 BOOL xfersend_sendBlock(void *block,int length,int *maxbuf)
514 char *p=(char *)block;
523 if (xfersend_sendbuf(p,send)==FALSE)