alsa.audio: move handling of XRUN when writting to the slave task
[AROS.git] / workbench / devs / clipboard / clipboard.c
blob3641faba6ce77f60df15d71988f504283347fb6b
1 /*
2 Copyright © 1998-2009, The AROS Development Team. All rights reserved.
3 $Id$
5 Clipboard device.
6 */
8 /****************************************************************************************/
10 #define AROS_ALMOST_COMPATIBLE 1
11 #include <exec/resident.h>
12 #include <devices/clipboard.h>
13 #include <devices/newstyle.h>
14 #include <exec/io.h>
15 #include <exec/initializers.h>
16 #include <proto/exec.h>
17 #include <proto/dos.h>
18 #include <proto/utility.h>
19 #include <clib/alib_protos.h>
20 #include <exec/memory.h>
21 #include <exec/errors.h>
22 #include <exec/lists.h>
23 #include <aros/libcall.h>
24 #include <aros/symbolsets.h>
25 #include "clipboard_intern.h"
26 #define DEBUG 0
27 #include <aros/debug.h>
28 #include <stdlib.h>
29 #include <stdio.h>
31 #include LC_LIBDEFS_FILE
33 /****************************************************************************************/
34 #ifndef __MORPHOS__
35 #define NEWSTYLE_DEVICE 1
36 #endif
38 #define ioClip(x) ((struct IOClipReq *)x)
39 #define CBUn (((struct ClipboardUnit *)ioreq->io_Unit))
41 #define WRITEBUFSIZE 4096
43 /****************************************************************************************/
45 static void readCb(struct IORequest *ioreq, struct ClipboardBase *CBBase);
46 static void writeCb(struct IORequest *ioreq, struct ClipboardBase *CBBase);
47 static void updateCb(struct IORequest *ioreq, struct ClipboardBase *CBBase);
49 /****************************************************************************************/
51 #if NEWSTYLE_DEVICE
53 static const UWORD SupportedCommands[] =
55 CMD_READ,
56 CMD_WRITE,
57 CMD_UPDATE,
58 CBD_CHANGEHOOK,
59 CBD_POST,
60 CBD_CURRENTREADID,
61 CBD_CURRENTWRITEID,
62 NSCMD_DEVICEQUERY,
66 #endif
68 /****************************************************************************************/
70 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR CBBase)
72 InitSemaphore(&CBBase->cb_SignalSemaphore);
73 NEWLIST(&CBBase->cb_UnitList);
74 NEWLIST(&CBBase->cb_HookList);
76 return TRUE;
79 /****************************************************************************************/
80 #ifndef __MORPHOS__
82 /* Putchar procedure needed by RawDoFmt() */
84 AROS_UFH2(void, putchr,
85 AROS_UFHA(UBYTE, chr, D0),
86 AROS_UFHA(STRPTR *, p, A3))
88 AROS_USERFUNC_INIT
89 *(*p)++=chr;
90 AROS_USERFUNC_EXIT
93 /****************************************************************************************/
95 #define cb_sprintf(CBBase, buffer, format, ...) \
96 ({ IPTR _args[]={__VA_ARGS__}; APTR bufptr = buffer; RawDoFmt(format, _args, (VOID_FUNC)AROS_ASMSYMNAME(putchr), &bufptr); })
98 #else
100 /* NOTE: Use 68k putch so that we don't bork with 68k localelib - Piru */
101 static const UWORD putch[] = {0x16c0, 0x4e75};
103 #define cb_sprintf(CBBase, buffer, format, ...) \
104 ({ ULONG _args[]={__VA_ARGS__}; RawDoFmt(format, _args, (void (*)(void)) putch, buffer); })
106 #endif
109 /****************************************************************************************/
111 static int GM_UNIQUENAME(Open)
113 LIBBASETYPEPTR CBBase,
114 struct IORequest *ioreq,
115 ULONG unitnum,
116 ULONG flags
119 BPTR tempLock = 0;
120 BOOL found = FALSE; /* Does the unit already exist? */
121 struct Node *tempNode; /* Temporary variable used to see if a unit
122 already exists */
124 D(bug("clipboard.device/open: ioreq 0x%lx unitnum %ld flags 0x%lx\n",ioreq,unitnum,flags));
126 if(unitnum > 255)
128 D(bug("clipboard.device/open: unitnum too large\n"));
129 ioClip(ioreq)->io_Error = IOERR_OPENFAIL;
130 return FALSE;
133 #ifndef __MORPHOS__
134 /* FIXME: You shouldn't check this..only leads to trouble */
135 if (ioreq->io_Message.mn_Length < sizeof(struct IOClipReq))
137 D(bug("clipboard.device/open: IORequest structure passed to OpenDevice is too small!\n"));
138 ioreq->io_Error = IOERR_OPENFAIL;
139 return FALSE;
141 #endif
143 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
145 /* Set up clipboard directory if we are the first opener */
147 if(CBBase->cb_ClipDir == NULL)
149 /* Disable dos requesters */
150 struct Process *pr = (struct Process*)FindTask(NULL);
151 APTR oldWindowPtr = pr->pr_WindowPtr;
152 pr->pr_WindowPtr = (APTR)-1;
154 D(bug("clipboard.device/Checking for CLIPS:\n"));
156 if (!(tempLock = Lock("CLIPS:", ACCESS_READ)))
158 /* CLIPS: is not assigned - revert to ram:Clipboards */
160 D(bug("clipboard.device/CLIPS: not found\n"));
161 D(bug("clipboard.device/Checking for ram:\n"));
163 if (!(tempLock = Lock("ram:", ACCESS_READ)))
165 D(bug("clipboard.device/ram: Not found."));
166 ioreq->io_Error = IOERR_OPENFAIL;
168 else
170 D(bug("clipboard.device/Found ram:\n"));
171 D(bug("clipboard.device/Checking for ram:clipboards\n"));
173 if (!(tempLock = Lock("ram:clipboards", ACCESS_READ)))
175 D(bug("clipboard.device/Not found -- creating ram:Clipboards.\n"));
176 if (!(tempLock = CreateDir("ram:clipboards")))
178 D(bug("clipboard.device/can't create clipboards file\n"));
179 ioreq->io_Error = IOERR_OPENFAIL;
183 CBBase->cb_ClipDir = "ram:clipboards/";
185 else
187 D(bug("clipboard.device/Found CLIPS:\n"));
188 CBBase->cb_ClipDir = "CLIPS:";
191 pr->pr_WindowPtr = oldWindowPtr;
193 /* Release the possible lock we have made */
194 UnLock(tempLock);
196 if (ioreq->io_Error)
198 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
199 return FALSE;
203 ForeachNode(&CBBase->cb_UnitList, tempNode)
205 D(bug("clipboard.device/ UnitNode 0x%lx Unit %ld\n",tempNode,tempNode->ln_Type));
206 if(tempNode->ln_Type == unitnum)
208 D(bug("clipboard.device/ found UnitNode\n"));
209 found = TRUE;
210 break;
214 if(found == FALSE)
216 D(bug("clipboard.device/Building unit...\n"));
218 if ((ioreq->io_Unit = (struct Unit *)AllocMem(sizeof(struct ClipboardUnit),
219 MEMF_CLEAR | MEMF_PUBLIC)))
221 CBUn->cu_Head.cu_UnitNum = unitnum;
222 CBUn->cu_Head.cu_Node.ln_Type = unitnum;
223 CBUn->cu_PostID = 0;
224 CBUn->cu_WriteID = 0;
226 NEWLIST((struct List*) &CBUn->cu_PostRequesters);
227 InitSemaphore(&CBUn->cu_UnitLock);
229 /* Construct clipboard unit filename. */
230 cb_sprintf(CBBase, CBUn->cu_clipFilename, "%s%lu", (IPTR)CBBase->cb_ClipDir,
231 (IPTR)unitnum);
233 CBUn->cu_Satisfy.sm_Unit = unitnum;
235 /* Initialization is done, and everything went OK. Add unit to the
236 list of clipboard units. */
237 ADDHEAD((struct List *)&CBBase->cb_UnitList, (struct Node *)CBUn);
239 /* Check if there is already a clipboard file for this unit existing.
240 If yes, then set WriteID to 1 so that CMD_READing works, and
241 also setup clipSize */
243 if ((CBUn->cu_clipFile = Open(CBUn->cu_clipFilename, MODE_OLDFILE)))
245 if (Seek(CBUn->cu_clipFile, 0, OFFSET_END) != -1)
247 CBUn->cu_clipSize = Seek(CBUn->cu_clipFile, 0, OFFSET_BEGINNING);
249 D(bug("clipboard.device/ <%s> clipsize %ld\n",CBUn->cu_clipFilename,CBUn->cu_clipSize));
250 if (CBUn->cu_clipSize != (ULONG)-1)
252 D(bug("clipboard.device/ WriteID set\n"));
253 CBUn->cu_WriteID = 1;
256 Close(CBUn->cu_clipFile);
257 CBUn->cu_clipFile = 0;
259 else
261 D(bug("clipboard.device/no <%s> file\n",CBUn->cu_clipFilename));
264 else
266 D(bug("clipboard.device/Couldn't alloc Unit\n"));
267 ioreq->io_Error = IOERR_OPENFAIL;
271 else
273 ioreq->io_Unit = (struct Unit *)tempNode;
276 if ((ioreq->io_Error == 0) && CBUn)
278 CBUn->cu_OpenCnt++;
280 else if (CBUn && (found == FALSE))
282 FreeMem(CBUn, sizeof(struct ClipboardUnit));
285 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
287 return TRUE;
290 /****************************************************************************************/
292 static int GM_UNIQUENAME(Close)
294 LIBBASETYPEPTR CBBase,
295 struct IORequest *ioreq
298 D(bug("clipboard.device/close:ioreq 0x%lx\n",ioreq));
300 /* Let any following attemps to use the device crash hard. */
301 ioreq->io_Device = (struct Device *)-1;
303 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
305 CBUn->cu_OpenCnt--;
307 D(bug("clipboard.device/close: unitcnt %ld\n",CBUn->cu_OpenCnt));
309 if(CBUn->cu_OpenCnt == 0)
311 D(bug("clipboard.device/close: removeunit\n",ioreq));
312 REMOVE((struct Node *)ioreq->io_Unit);
313 FreeMem(ioreq->io_Unit, sizeof(struct ClipboardUnit));
315 /* Let any following attemps to use the device crash hard. */
316 ioreq->io_Unit = (struct Unit *) -1;
319 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
321 return TRUE;
324 /****************************************************************************************/
326 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
327 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
328 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
330 /****************************************************************************************/
332 AROS_LH1(void, beginio,
333 AROS_LHA(struct IORequest *, ioreq, A1),
334 struct ClipboardBase *, CBBase, 5, Clipboard)
336 AROS_LIBFUNC_INIT
338 ioreq->io_Error = 0;
340 switch (ioreq->io_Command)
342 #if NEWSTYLE_DEVICE
343 case NSCMD_DEVICEQUERY:
344 if(ioClip(ioreq)->io_Length < ((IPTR)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
346 ioreq->io_Error = IOERR_BADLENGTH;
348 else
350 struct NSDeviceQueryResult *d;
352 d = (struct NSDeviceQueryResult *)ioClip(ioreq)->io_Data;
354 d->DevQueryFormat = 0;
355 d->SizeAvailable = sizeof(struct NSDeviceQueryResult);
356 d->DeviceType = NSDEVTYPE_CLIPBOARD;
357 d->DeviceSubType = 0;
358 d->SupportedCommands = (UWORD *)SupportedCommands;
360 ioClip(ioreq)->io_Actual = sizeof(struct NSDeviceQueryResult);
362 break;
363 #endif
365 case CBD_CHANGEHOOK:
367 D(bug("clipboard.device/Command: CBD_CHANGEHOOK\n"));
369 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
371 /* io_Length is used as a means of specifying if the hook
372 should be added or removed. */
373 switch(ioClip(ioreq)->io_Length)
375 case 0:
376 REMOVE((struct Node *)(ioClip(ioreq)->io_Data));
377 break;
379 case 1:
380 ADDHEAD((struct List *)&CBBase->cb_HookList,
381 (struct Node *)ioClip(ioreq)->io_Data);
382 break;
384 default:
385 ioreq->io_Error = IOERR_BADLENGTH;
386 break;
388 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
389 break;
391 case CMD_WRITE:
393 D(bug("clipboard.device/Command: CMD_WRITE\n"));
395 writeCb(ioreq, CBBase);
396 break;
398 case CMD_READ:
400 D(bug("clipboard.device/Command: CMD_READ\n"));
402 /* Get new ID if this is the beginning of a read operation */
403 if(ioClip(ioreq)->io_ClipID == 0)
405 D(bug("clipboard.device/CMD_READ: Trying to get unit lock. Calling ObtainSemaphore [me=%08lx].\n", FindTask(NULL)));
407 ObtainSemaphore(&CBUn->cu_UnitLock);
409 D(bug("clipboard.device/CMD_READ: Got unit lock.\n"));
411 /* If the last write was actually a POST, we must tell
412 the POSTer to WRITE the clip immediately, and we
413 will wait until he have done so. Then we check
414 again in case somebody managed to sneek in a
415 CBD_POST after the CMD_UPDATE. */
417 while(CBUn->cu_WriteID != 0 &&
418 CBUn->cu_WriteID == CBUn->cu_PostID)
420 struct PostRequest pr = {
421 { NULL, NULL },
422 FindTask(NULL)
425 /* Make sure we are signalled. */
426 ADDTAIL((struct List*) &CBUn->cu_PostRequesters, (struct Node*) &pr);
428 /* A poster reading will deadlock that process
429 * until somebody else writes to the
430 * clipboard. AmigaOS behaves exactly the same so
431 * it's ok. It's just plain stupid anyway. */
433 if (CBUn->cu_PostPort)
435 D(bug("clipboard.device/Command: CMD_READ..notify PostPort 0x%lx\n", CBUn->cu_PostPort));
437 CBUn->cu_Satisfy.sm_ClipID = CBUn->cu_PostID;
438 PutMsg(CBUn->cu_PostPort, (struct Message *)&CBUn->cu_Satisfy);
439 CBUn->cu_PostPort = NULL;
441 else
443 D(bug("clipboard.device/Command: no PostPort [me=%08lx]\n", FindTask(NULL)));
446 Forbid();
447 ReleaseSemaphore(&CBUn->cu_UnitLock);
448 SetSignal(0, SIGF_SINGLE);
449 Wait(SIGF_SINGLE);
450 Permit();
451 D(bug("Got SIGF_SINGLE [me=%08lx]\n",FindTask(NULL)));
452 ObtainSemaphore(&CBUn->cu_UnitLock);
453 D(bug("Got semaphore[me=%08lx]\n",FindTask(NULL)));
455 if(pr.pr_Link.mln_Succ->mln_Succ != NULL)
457 /* Wake up next reader */
458 Signal(((struct PostRequest*) pr.pr_Link.mln_Succ)->pr_Waiter, SIGF_SINGLE);
461 Remove((struct Node*) &pr);
464 CBUn->cu_ReadID++;
465 ioClip(ioreq)->io_ClipID = CBUn->cu_ReadID;
467 CBUn->cu_clipFile = Open(CBUn->cu_clipFilename, MODE_OLDFILE);
469 if(!CBUn->cu_clipFile)
471 D(bug("clipboard.device/CMD_READ: No clip file. Calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL)));
472 ReleaseSemaphore(&CBUn->cu_UnitLock);
473 ioClip(ioreq)->io_ClipID = -1;
474 ioClip(ioreq)->io_Actual = 0;
475 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
476 break;
479 else if(ioClip(ioreq)->io_ClipID != CBUn->cu_ReadID)
481 D(bug("clipboard.device/CMD_READ: Invalid clip id.\n"));
482 ioClip(ioreq)->io_Actual = 0;
483 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
484 break;
487 readCb(ioreq, CBBase);
489 break;
492 case CMD_UPDATE:
493 D(bug("clipboard.device/Command: CMD_UPDATE\n"));
495 updateCb(ioreq, CBBase);
496 break;
499 case CBD_POST:
500 D(bug("clipboard.device/Command: CBD_POST [me=%08lx]\n", FindTask(NULL)));
501 ObtainSemaphore(&CBUn->cu_UnitLock);
503 CBUn->cu_WriteID++;
504 CBUn->cu_PostID = CBUn->cu_WriteID;
505 CBUn->cu_PostPort = (struct MsgPort *)ioClip(ioreq)->io_Data;
507 ioClip(ioreq)->io_ClipID = CBUn->cu_PostID;
509 ReleaseSemaphore(&CBUn->cu_UnitLock);
511 D(bug("clipboard.device/CBD_POST: Calling monitoring hooks\n"));
513 /* Call monitoring hooks. */
514 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
516 struct Node *tnode;
517 struct ClipHookMsg chmsg;
519 chmsg.chm_Type = 0;
520 chmsg.chm_ChangeCmd = CBD_POST;
521 chmsg.chm_ClipID = CBUn->cu_PostID;
523 ForeachNode(&CBBase->cb_HookList, tnode)
525 D(bug("Calling hook %08x\n",tnode));
526 CallHookA((struct Hook *)tnode, CBUn, &chmsg);
528 D(bug("Done\n"));
530 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
532 D(bug("clipboard.device/CBD_POST: Called monitoring hooks\n"));
534 #if 0
535 // This does not seem to be robust enough; it can lead to
536 // a ping-pong effect. Never mind then.
538 ObtainSemaphore(&CBUn->cu_UnitLock);
540 if(!IsListEmpty((struct List*) &CBUn->cu_PostRequesters))
542 /* Normally, this can never happen. However, if an app
543 deadlocked by posting and then reading, try to make
544 this CBD_POST turn into a CMD_WRITE immediately. */
546 D(bug("clipboard.device/Command: CMD_POST..notify PostPort 0x%lx\n", CBUn->cu_PostPort));
548 CBUn->cu_Satisfy.sm_ClipID = CBUn->cu_PostID;
549 PutMsg(CBUn->cu_PostPort, (struct Message *)&CBUn->cu_Satisfy);
550 CBUn->cu_PostPort = NULL;
553 ReleaseSemaphore(&CBUn->cu_UnitLock);
554 #endif
555 break;
558 case CBD_CURRENTREADID:
559 D(bug("clipboard.device/Command: CBD_CURRENTREADID\n"));
560 ioClip(ioreq)->io_ClipID = CBUn->cu_WriteID;
561 /* NOTE: NOT A BUG! Was PostID. Note that AmigaOS really has a
562 ReadID counter that is *almost* always the same as WriteID. */
563 break;
566 case CBD_CURRENTWRITEID:
567 D(bug("clipboard.device/Command: CBD_CURRENTWRITEID\n"));
568 ioClip(ioreq)->io_ClipID = CBUn->cu_WriteID;
569 break;
572 default:
573 D(bug("clipboard.device/Command: <UNKNOWN> (%d = 0x%x)\n", ioreq->io_Command));
574 ioreq->io_Error = IOERR_NOCMD;
575 break;
577 } /* switch (ioreq->io_Command) */
579 /* If the quick bit is not set, send the message to the port */
580 if(!(ioreq->io_Flags & IOF_QUICK))
582 ReplyMsg(&ioreq->io_Message);
585 AROS_LIBFUNC_EXIT
588 /****************************************************************************************/
590 AROS_LH1(LONG, abortio,
591 AROS_LHA(struct IORequest *, ioreq, A1),
592 struct ClipboardBase *, CBBase, 6, Clipboard)
594 AROS_LIBFUNC_INIT
596 /* Keep compiler happy */
597 (void) ioreq;
598 (void) CBBase;
600 D(bug("clipboard.device/abortio: ioreq 0x%lx\n",ioreq));
601 /* Nothing to abort */
602 return 0;
604 AROS_LIBFUNC_EXIT
607 /****************************************************************************************/
609 static void readCb(struct IORequest *ioreq, struct ClipboardBase *CBBase)
611 /* Is there anything to be read? */
612 if(CBUn->cu_WriteID == 0)
614 D(bug("clipboard.device/readcb: nothing to read. setting IOERR_ABORTED as error and releasing semaphore [me=%08lx]\n", FindTask(NULL)));
615 Close(CBUn->cu_clipFile);
616 CBUn->cu_clipFile = 0;
617 ReleaseSemaphore(&CBUn->cu_UnitLock);
618 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
619 ioClip(ioreq)->io_Actual = 0;
620 ioClip(ioreq)->io_ClipID = -1;
621 return;
624 if(ioClip(ioreq)->io_Offset >= CBUn->cu_clipSize)
626 D(bug("clipboard.device/readCb: detected \"end of file\". Closing clipfile and releasing semaphore [me=%08lx]\n", FindTask(NULL)));
627 Close(CBUn->cu_clipFile);
628 CBUn->cu_clipFile = 0;
629 ReleaseSemaphore(&CBUn->cu_UnitLock);
630 ioClip(ioreq)->io_Actual = 0;
631 ioClip(ioreq)->io_ClipID = -1;
632 return;
635 if (!ioClip(ioreq)->io_Data)
638 * according to the autodocs, io_Offset is incremented by io_Actual
639 * as if io_Length bytes had been read.
641 if(ioClip(ioreq)->io_Offset + ioClip(ioreq)->io_Length > CBUn->cu_clipSize)
643 /* Cannot read more bytes as there are in the clipboard.
644 * On amigaOS, this can be used to get the current size of the
645 * clipboard content.
647 ioClip(ioreq)->io_Actual = CBUn->cu_clipSize - ioClip(ioreq)->io_Offset;
648 D(bug("clipboard.device/readCb: reached end of clipboard data\n"));
650 else
652 /* we pretend to read the requested length */
653 ioClip(ioreq)->io_Actual = ioClip(ioreq)->io_Length;
656 else
658 D(bug("clipboard.device/readCb: Doing read Seek() at offset %d.\n",
659 ioClip(ioreq)->io_Offset));
661 Seek(CBUn->cu_clipFile, ioClip(ioreq)->io_Offset, OFFSET_BEGINNING);
663 ioClip(ioreq)->io_Actual = Read(CBUn->cu_clipFile, ioClip(ioreq)->io_Data,
664 ioClip(ioreq)->io_Length);
666 if (ioClip(ioreq)->io_Length >= 4)
668 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x%02x%02x%02x (%c%c%c%c)\n",
669 ioClip(ioreq)->io_Length,
670 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
671 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
672 ((UBYTE *)ioClip(ioreq)->io_Data)[2],
673 ((UBYTE *)ioClip(ioreq)->io_Data)[3],
674 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
675 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
676 ((UBYTE *)ioClip(ioreq)->io_Data)[2],
677 ((UBYTE *)ioClip(ioreq)->io_Data)[3]));
679 else if (ioClip(ioreq)->io_Length == 2)
681 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x%02x (%c%c)\n",
682 ioClip(ioreq)->io_Length,
683 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
684 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
685 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
686 ((UBYTE *)ioClip(ioreq)->io_Data)[1]));
688 else if (ioClip(ioreq)->io_Length == 1)
690 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x (%c)\n",
691 ioClip(ioreq)->io_Length,
692 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
693 ((UBYTE *)ioClip(ioreq)->io_Data)[0]));
695 else
697 D(bug("clipboard.device/readCb: Did Read nothing: data length = 0 data = 0x%x\n",
698 ioClip(ioreq)->io_Data));
703 ioClip(ioreq)->io_Offset += ioClip(ioreq)->io_Actual;
706 * I am not sure, if a Close is the right thing to do, even if io_Data was NULL.
707 * But it should not harm either.
709 if (ioClip(ioreq)->io_Actual == 0)
711 Close(CBUn->cu_clipFile);
712 CBUn->cu_clipFile = 0;
713 D(bug("clipboard.device/readCb: io_Actual=0. Calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL)));
714 ReleaseSemaphore(&CBUn->cu_UnitLock);
715 ioClip(ioreq)->io_ClipID = -1;
719 /****************************************************************************************/
721 static void writeCb(struct IORequest *ioreq, struct ClipboardBase *CBBase)
723 D(bug("clipboard.device/writeCb: Trying to get unit lock. Calling ObtainSemaphore [me=%08lx]\n", FindTask(NULL)));
724 ObtainSemaphore(&CBUn->cu_UnitLock);
725 D(bug("clipboard.device/writeCb: Got unit lock.\n"));
727 if(ioClip(ioreq)->io_ClipID == 0 ||
728 ioClip(ioreq)->io_ClipID == CBUn->cu_PostID)
730 /* A new write begins... */
732 CBUn->cu_clipSize = 0;
734 if(ioClip(ioreq)->io_ClipID == 0)
736 CBUn->cu_WriteID++;
737 ioClip(ioreq)->io_ClipID = CBUn->cu_WriteID;
740 /* No more POST writes accepted */
741 CBUn->cu_PostID = 0;
743 if (!(CBUn->cu_clipFile = Open(CBUn->cu_clipFilename, MODE_NEWFILE)))
745 D(bug("clipboard.device/writeCb: Opening clipfile in MODE_NEWFILE failed. Releasing Semaphore [me=%08lx]\n", FindTask(NULL)));
746 ReleaseSemaphore(&CBUn->cu_UnitLock);
747 ioClip(ioreq)->io_Error = IOERR_ABORTED;
748 ioClip(ioreq)->io_Actual = 0;
749 ioClip(ioreq)->io_ClipID = -1;
750 return;
753 D(bug("clipboard.device/writeCb: Opened file %s\n", CBUn->cu_clipFilename));
755 else if(ioClip(ioreq)->io_ClipID == CBUn->cu_WriteID)
757 D(bug("We already have the semaphore. [me=%08lx]\n", FindTask(NULL)));
758 ReleaseSemaphore(&CBUn->cu_UnitLock);
760 /* Continue the previous write */
762 else
764 D(bug("Invalid ClipID. Releasing Semaphore [me=%08lx]\n", FindTask(NULL)));
765 ReleaseSemaphore(&CBUn->cu_UnitLock);
767 /* Error */
768 ioClip(ioreq)->io_Error = IOERR_ABORTED;
769 ioClip(ioreq)->io_Actual = 0;
770 return;
773 if(ioClip(ioreq)->io_Offset > CBUn->cu_clipSize)
775 ULONG len = ioClip(ioreq)->io_Offset - CBUn->cu_clipSize;
776 ULONG buflen = len > WRITEBUFSIZE ? WRITEBUFSIZE : len;
777 UBYTE *buf = AllocMem(buflen, MEMF_CLEAR | MEMF_PUBLIC);
779 Seek(CBUn->cu_clipFile, 0, OFFSET_END);
781 if (buf)
783 while(len)
785 ULONG size = len > WRITEBUFSIZE ? WRITEBUFSIZE : len;
787 Write(CBUn->cu_clipFile, buf, size);
788 len -= size;
790 FreeMem(buf, buflen);
793 Seek(CBUn->cu_clipFile, ioClip(ioreq)->io_Offset, OFFSET_BEGINNING);
795 D(bug("clipboard.device/writeCb: Did Seek(), offset = %d\n", ioClip(ioreq)->io_Offset));
797 if (ioClip(ioreq)->io_Length >= 4)
799 D(bug("clipboard.device/Doing Write: data length = %d data = %02x%02x%02x%02x (%c%c%c%c)\n",
800 ioClip(ioreq)->io_Length,
801 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
802 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
803 ((UBYTE *)ioClip(ioreq)->io_Data)[2],
804 ((UBYTE *)ioClip(ioreq)->io_Data)[3],
805 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
806 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
807 ((UBYTE *)ioClip(ioreq)->io_Data)[2],
808 ((UBYTE *)ioClip(ioreq)->io_Data)[3]));
810 else if (ioClip(ioreq)->io_Length == 2)
812 D(bug("clipboard.device/Doing Write: data length = %d data = %02x%02x (%c%c)\n",
813 ioClip(ioreq)->io_Length,
814 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
815 ((UBYTE *)ioClip(ioreq)->io_Data)[1],
816 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
817 ((UBYTE *)ioClip(ioreq)->io_Data)[1]));
819 else if (ioClip(ioreq)->io_Length == 1)
821 D(bug("clipboard.device/Doing Write: data length = %d data = %02x (%c)\n",
822 ioClip(ioreq)->io_Length,
823 ((UBYTE *)ioClip(ioreq)->io_Data)[0],
824 ((UBYTE *)ioClip(ioreq)->io_Data)[0]));
827 else
829 D(bug("clipboard.device/Doing Write: Not really!!: data length = 0 data = 0x%x\n",
830 ioClip(ioreq)->io_Data));
833 if (ioClip(ioreq)->io_Length)
835 ioClip(ioreq)->io_Actual = Write(CBUn->cu_clipFile, ioClip(ioreq)->io_Data, ioClip(ioreq)->io_Length);
837 else
839 ioClip(ioreq)->io_Actual = 0; /* texteditor.mcc does 0-length writes */
842 if ((LONG)ioClip(ioreq)->io_Actual == -1)
844 D(bug("clipboard.device/writeCb: write failed\n"));
845 Close(CBUn->cu_clipFile);
846 CBUn->cu_clipFile = 0;
847 D(bug("clipboard.device/writeCb: releasing semaphore [me=%08lx]\n", FindTask(NULL)));
848 ReleaseSemaphore(&CBUn->cu_UnitLock);
849 ioClip(ioreq)->io_Error = IOERR_ABORTED;
850 ioClip(ioreq)->io_Actual = 0;
851 ioClip(ioreq)->io_ClipID = -1;
853 else
855 ioClip(ioreq)->io_Offset += ioClip(ioreq)->io_Actual;
856 if(ioClip(ioreq)->io_Offset > CBUn->cu_clipSize)
858 CBUn->cu_clipSize = ioClip(ioreq)->io_Offset;
863 /****************************************************************************************/
865 static void updateCb(struct IORequest *ioreq, struct ClipboardBase *CBBase)
867 if(CBUn->cu_WriteID != 0 && CBUn->cu_WriteID == ioClip(ioreq)->io_ClipID)
869 D(bug("clipboard.device/updateCb: Closing ClipFile\n"));
871 Close(CBUn->cu_clipFile);
872 CBUn->cu_clipFile = 0;
874 if(CBUn->cu_PostRequesters.mlh_Head->mln_Succ != NULL)
876 /* Wake up first reader */
877 D(bug("clipboard.device/updateCb: Waking up %08lx\n", ((struct PostRequest*) CBUn->cu_PostRequesters.mlh_Head)->pr_Waiter));
878 Signal(((struct PostRequest*) CBUn->cu_PostRequesters.mlh_Head)->pr_Waiter, SIGF_SINGLE);
880 D(bug("clipboard.device/updateCb: calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL)));
882 ReleaseSemaphore(&CBUn->cu_UnitLock);
884 D(bug("clipboard.device/updateCb: Calling monitoring hooks\n"));
886 /* Call monitoring hooks. */
887 ObtainSemaphore(&CBBase->cb_SignalSemaphore);
889 struct Node *tnode;
890 struct ClipHookMsg chmsg;
892 chmsg.chm_Type = 0;
893 chmsg.chm_ChangeCmd = CMD_UPDATE;
894 chmsg.chm_ClipID = ioClip(ioreq)->io_ClipID;
896 ForeachNode(&CBBase->cb_HookList, tnode)
898 D(bug("Calling hook %08x\n",tnode));
899 CallHookA((struct Hook *)tnode, CBUn, &chmsg);
901 D(bug("Done\n"));
903 ReleaseSemaphore(&CBBase->cb_SignalSemaphore);
905 D(bug("clipboard.device/updateCb: Called monitoring hooks\n"));
907 else
909 ioClip(ioreq)->io_Error = IOERR_ABORTED;
910 ioClip(ioreq)->io_Actual = 0;
913 ioClip(ioreq)->io_ClipID = -1;
915 D(bug("clipboard.device/updateCb: end of function [me=%08lx]\n", FindTask(NULL)));
919 /****************************************************************************************/