2 Copyright © 1998-2008, The AROS Development Team. All rights reserved.
8 /****************************************************************************************/
10 #define AROS_ALMOST_COMPATIBLE 1
11 #include <exec/resident.h>
12 #include <devices/clipboard.h>
13 #include <devices/newstyle.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"
27 #include <aros/debug.h>
31 #include LC_LIBDEFS_FILE
33 /****************************************************************************************/
35 #define NEWSTYLE_DEVICE 1
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 /****************************************************************************************/
53 static const UWORD SupportedCommands
[] =
68 /****************************************************************************************/
70 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR CBBase
)
72 InitSemaphore(&CBBase
->cb_SignalSemaphore
);
73 NEWLIST(&CBBase
->cb_UnitList
);
74 NEWLIST(&CBBase
->cb_HookList
);
79 /****************************************************************************************/
82 /* Putchar procedure needed by RawDoFmt() */
84 AROS_UFH2(void, putchr
,
85 AROS_UFHA(UBYTE
, chr
, D0
),
86 AROS_UFHA(STRPTR
*, p
, A3
))
93 /****************************************************************************************/
95 #define cb_sprintf(CBBase, buffer, format, ...) \
96 ({ ULONG _args[]={__VA_ARGS__}; APTR bufptr = buffer; RawDoFmt(format, _args, (VOID_FUNC)AROS_ASMSYMNAME(putchr), &bufptr); })
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); })
109 /****************************************************************************************/
111 static int GM_UNIQUENAME(Open
)
113 LIBBASETYPEPTR CBBase
,
114 struct IORequest
*ioreq
,
120 BOOL found
= FALSE
; /* Does the unit already exist? */
121 struct Node
*tempNode
; /* Temporary variable used to see if a unit
124 D(bug("clipboard.device/open: ioreq 0x%lx unitnum %ld flags 0x%lx\n",ioreq
,unitnum
,flags
));
128 D(bug("clipboard.device/open: unitnum too large\n"));
129 ioClip(ioreq
)->io_Error
= IOERR_OPENFAIL
;
134 #warning "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
;
143 ObtainSemaphore(&CBBase
->cb_SignalSemaphore
);
145 /* Set up clipboard directory if we are the first opener */
147 if(CBBase
->cb_ClipDir
== NULL
)
149 D(bug("clipboard.device/Checking for CLIPS:\n"));
151 if (!(tempLock
= Lock("CLIPS:", ACCESS_READ
)))
153 /* CLIPS: is not assigned - revert to ram:Clipboards */
155 D(bug("clipboard.device/CLIPS: not found\n"));
156 D(bug("clipboard.device/Checking for ram:\n"));
158 if (!(tempLock
= Lock("ram:", ACCESS_READ
)))
160 D(bug("clipboard.device/ram: Not found."));
161 ioreq
->io_Error
= IOERR_OPENFAIL
;
165 D(bug("clipboard.device/Found ram:\n"));
166 D(bug("clipboard.device/Checking for ram:clipboards\n"));
168 if (!(tempLock
= Lock("ram:clipboards", ACCESS_READ
)))
170 D(bug("clipboard.device/Not found -- creating ram:Clipboards.\n"));
171 if (!(tempLock
= CreateDir("ram:clipboards")))
173 D(bug("clipboard.device/can't create clipboards file\n"));
174 ioreq
->io_Error
= IOERR_OPENFAIL
;
178 CBBase
->cb_ClipDir
= "ram:clipboards/";
182 D(bug("clipboard.device/Found CLIPS:\n"));
183 CBBase
->cb_ClipDir
= "CLIPS:";
186 /* Release the possible lock we have made */
191 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
196 ForeachNode(&CBBase
->cb_UnitList
, tempNode
)
198 D(bug("clipboard.device/ UnitNode 0x%lx Unit %ld\n",tempNode
,tempNode
->ln_Type
));
199 if(tempNode
->ln_Type
== unitnum
)
201 D(bug("clipboard.device/ found UnitNode\n"));
209 D(bug("clipboard.device/Building unit...\n"));
211 if ((ioreq
->io_Unit
= (struct Unit
*)AllocMem(sizeof(struct ClipboardUnit
),
212 MEMF_CLEAR
| MEMF_PUBLIC
)))
214 CBUn
->cu_Head
.cu_UnitNum
= unitnum
;
215 CBUn
->cu_Head
.cu_Node
.ln_Type
= unitnum
;
217 CBUn
->cu_WriteID
= 0;
219 NEWLIST((struct List
*) &CBUn
->cu_PostRequesters
);
220 InitSemaphore(&CBUn
->cu_UnitLock
);
222 /* Construct clipboard unit filename. */
223 cb_sprintf(CBBase
, CBUn
->cu_clipFilename
, "%s%lu", (ULONG
) CBBase
->cb_ClipDir
,
226 CBUn
->cu_Satisfy
.sm_Unit
= unitnum
;
228 /* Initialization is done, and everything went OK. Add unit to the
229 list of clipboard units. */
230 ADDHEAD((struct List
*)&CBBase
->cb_UnitList
, (struct Node
*)CBUn
);
232 /* Check if there is already a clipboard file for this unit existing.
233 If yes, then set WriteID to 1 so that CMD_READing works, and
234 also setup clipSize */
236 if ((CBUn
->cu_clipFile
= Open(CBUn
->cu_clipFilename
, MODE_OLDFILE
)))
238 if (Seek(CBUn
->cu_clipFile
, 0, OFFSET_END
) != -1)
240 CBUn
->cu_clipSize
= Seek(CBUn
->cu_clipFile
, 0, OFFSET_BEGINNING
);
242 D(bug("clipboard.device/ <%s> clipsize %ld\n",CBUn
->cu_clipFilename
,CBUn
->cu_clipSize
));
243 if (CBUn
->cu_clipSize
!= (ULONG
)-1)
245 D(bug("clipboard.device/ WriteID set\n"));
246 CBUn
->cu_WriteID
= 1;
249 Close(CBUn
->cu_clipFile
);
250 CBUn
->cu_clipFile
= 0;
254 D(bug("clipboard.device/no <%s> file\n",CBUn
->cu_clipFilename
));
259 D(bug("clipboard.device/Couldn't alloc Unit\n"));
260 ioreq
->io_Error
= IOERR_OPENFAIL
;
266 ioreq
->io_Unit
= (struct Unit
*)tempNode
;
269 if ((ioreq
->io_Error
== 0) && CBUn
)
273 else if (CBUn
&& (found
== FALSE
))
275 FreeMem(CBUn
, sizeof(struct ClipboardUnit
));
278 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
283 /****************************************************************************************/
285 static int GM_UNIQUENAME(Close
)
287 LIBBASETYPEPTR CBBase
,
288 struct IORequest
*ioreq
291 D(bug("clipboard.device/close:ioreq 0x%lx\n",ioreq
));
293 /* Let any following attemps to use the device crash hard. */
294 ioreq
->io_Device
= (struct Device
*)-1;
296 ObtainSemaphore(&CBBase
->cb_SignalSemaphore
);
300 D(bug("clipboard.device/close: unitcnt %ld\n",CBUn
->cu_OpenCnt
));
302 if(CBUn
->cu_OpenCnt
== 0)
304 D(bug("clipboard.device/close: removeunit\n",ioreq
));
305 REMOVE((struct Node
*)ioreq
->io_Unit
);
306 FreeMem(ioreq
->io_Unit
, sizeof(struct ClipboardUnit
));
308 /* Let any following attemps to use the device crash hard. */
309 ioreq
->io_Unit
= (struct Unit
*) -1;
312 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
317 /****************************************************************************************/
319 ADD2INITLIB(GM_UNIQUENAME(Init
), 0)
320 ADD2OPENDEV(GM_UNIQUENAME(Open
), 0)
321 ADD2CLOSEDEV(GM_UNIQUENAME(Close
), 0)
323 /****************************************************************************************/
325 AROS_LH1(void, beginio
,
326 AROS_LHA(struct IORequest
*, ioreq
, A1
),
327 struct ClipboardBase
*, CBBase
, 5, Clipboard
)
333 switch (ioreq
->io_Command
)
336 case NSCMD_DEVICEQUERY
:
337 if(ioClip(ioreq
)->io_Length
< ((LONG
)OFFSET(NSDeviceQueryResult
, SupportedCommands
)) + sizeof(UWORD
*))
339 ioreq
->io_Error
= IOERR_BADLENGTH
;
343 struct NSDeviceQueryResult
*d
;
345 d
= (struct NSDeviceQueryResult
*)ioClip(ioreq
)->io_Data
;
347 d
->DevQueryFormat
= 0;
348 d
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
349 d
->DeviceType
= NSDEVTYPE_CLIPBOARD
;
350 d
->DeviceSubType
= 0;
351 d
->SupportedCommands
= (UWORD
*)SupportedCommands
;
353 ioClip(ioreq
)->io_Actual
= sizeof(struct NSDeviceQueryResult
);
360 D(bug("clipboard.device/Command: CBD_CHANGEHOOK\n"));
362 ObtainSemaphore(&CBBase
->cb_SignalSemaphore
);
364 /* io_Length is used as a means of specifying if the hook
365 should be added or removed. */
366 switch(ioClip(ioreq
)->io_Length
)
369 REMOVE((struct Node
*)(ioClip(ioreq
)->io_Data
));
373 ADDHEAD((struct List
*)&CBBase
->cb_HookList
,
374 (struct Node
*)ioClip(ioreq
)->io_Data
);
378 ioreq
->io_Error
= IOERR_BADLENGTH
;
381 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
386 D(bug("clipboard.device/Command: CMD_WRITE\n"));
388 writeCb(ioreq
, CBBase
);
393 D(bug("clipboard.device/Command: CMD_READ\n"));
395 /* Get new ID if this is the beginning of a read operation */
396 if(ioClip(ioreq
)->io_ClipID
== 0)
398 D(bug("clipboard.device/CMD_READ: Trying to get unit lock. Calling ObtainSemaphore [me=%08lx].\n", FindTask(NULL
)));
400 ObtainSemaphore(&CBUn
->cu_UnitLock
);
402 D(bug("clipboard.device/CMD_READ: Got unit lock.\n"));
404 /* If the last write was actually a POST, we must tell
405 the POSTer to WRITE the clip immediately, and we
406 will wait until he have done so. Then we check
407 again in case somebody managed to sneek in a
408 CBD_POST after the CMD_UPDATE. */
410 while(CBUn
->cu_WriteID
!= 0 &&
411 CBUn
->cu_WriteID
== CBUn
->cu_PostID
)
413 struct PostRequest pr
= {
418 /* Make sure we are signalled. */
419 ADDTAIL((struct List
*) &CBUn
->cu_PostRequesters
, (struct Node
*) &pr
);
421 /* A poster reading will deadlock that process
422 * until somebody else writes to the
423 * clipboard. AmigaOS behaves exactly the same so
424 * it's ok. It's just plain stupid anyway. */
426 if (CBUn
->cu_PostPort
)
428 D(bug("clipboard.device/Command: CMD_READ..notify PostPort 0x%lx\n", CBUn
->cu_PostPort
));
430 CBUn
->cu_Satisfy
.sm_ClipID
= CBUn
->cu_PostID
;
431 PutMsg(CBUn
->cu_PostPort
, (struct Message
*)&CBUn
->cu_Satisfy
);
432 CBUn
->cu_PostPort
= NULL
;
436 D(bug("clipboard.device/Command: no PostPort [me=%08lx]\n", FindTask(NULL
)));
440 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
441 SetSignal(0, SIGF_SINGLE
);
444 D(bug("Got SIGF_SINGLE [me=%08lx]\n",FindTask(NULL
)));
445 ObtainSemaphore(&CBUn
->cu_UnitLock
);
446 D(bug("Got semaphore[me=%08lx]\n",FindTask(NULL
)));
448 if(pr
.pr_Link
.mln_Succ
->mln_Succ
!= NULL
)
450 /* Wake up next reader */
451 Signal(((struct PostRequest
*) pr
.pr_Link
.mln_Succ
)->pr_Waiter
, SIGF_SINGLE
);
454 Remove((struct Node
*) &pr
);
458 ioClip(ioreq
)->io_ClipID
= CBUn
->cu_ReadID
;
460 CBUn
->cu_clipFile
= Open(CBUn
->cu_clipFilename
, MODE_OLDFILE
);
462 if(!CBUn
->cu_clipFile
)
464 D(bug("clipboard.device/CMD_READ: No clip file. Calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL
)));
465 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
466 ioClip(ioreq
)->io_ClipID
= -1;
467 ioClip(ioreq
)->io_Actual
= 0;
468 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
472 else if(ioClip(ioreq
)->io_ClipID
!= CBUn
->cu_ReadID
)
474 D(bug("clipboard.device/CMD_READ: Invalid clip id.\n"));
475 ioClip(ioreq
)->io_Actual
= 0;
476 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
480 readCb(ioreq
, CBBase
);
486 D(bug("clipboard.device/Command: CMD_UPDATE\n"));
488 updateCb(ioreq
, CBBase
);
493 D(bug("clipboard.device/Command: CBD_POST [me=%08lx]\n", FindTask(NULL
)));
494 ObtainSemaphore(&CBUn
->cu_UnitLock
);
497 CBUn
->cu_PostID
= CBUn
->cu_WriteID
;
498 CBUn
->cu_PostPort
= (struct MsgPort
*)ioClip(ioreq
)->io_Data
;
500 ioClip(ioreq
)->io_ClipID
= CBUn
->cu_PostID
;
502 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
504 D(bug("clipboard.device/CBD_POST: Calling monitoring hooks\n"));
506 /* Call monitoring hooks. */
507 ObtainSemaphore(&CBBase
->cb_SignalSemaphore
);
510 struct ClipHookMsg chmsg
;
513 chmsg
.chm_ChangeCmd
= CBD_POST
;
514 chmsg
.chm_ClipID
= CBUn
->cu_PostID
;
516 ForeachNode(&CBBase
->cb_HookList
, tnode
)
518 D(bug("Calling hook %08x\n",tnode
));
519 CallHookA((struct Hook
*)tnode
, CBUn
, &chmsg
);
523 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
525 D(bug("clipboard.device/CBD_POST: Called monitoring hooks\n"));
528 // This does not seem to be robust enough; it can lead to
529 // a ping-pong effect. Never mind then.
531 ObtainSemaphore(&CBUn
->cu_UnitLock
);
533 if(!IsListEmpty((struct List
*) &CBUn
->cu_PostRequesters
))
535 /* Normally, this can never happen. However, if an app
536 deadlocked by posting and then reading, try to make
537 this CBD_POST turn into a CMD_WRITE immediately. */
539 D(bug("clipboard.device/Command: CMD_POST..notify PostPort 0x%lx\n", CBUn
->cu_PostPort
));
541 CBUn
->cu_Satisfy
.sm_ClipID
= CBUn
->cu_PostID
;
542 PutMsg(CBUn
->cu_PostPort
, (struct Message
*)&CBUn
->cu_Satisfy
);
543 CBUn
->cu_PostPort
= NULL
;
546 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
551 case CBD_CURRENTREADID
:
552 D(bug("clipboard.device/Command: CBD_CURRENTREADID\n"));
553 ioClip(ioreq
)->io_ClipID
= CBUn
->cu_WriteID
;
554 /* NOTE: NOT A BUG! Was PostID. Note that AmigaOS really has a
555 ReadID counter that is *almost* always the same as WriteID. */
559 case CBD_CURRENTWRITEID
:
560 D(bug("clipboard.device/Command: CBD_CURRENTWRITEID\n"));
561 ioClip(ioreq
)->io_ClipID
= CBUn
->cu_WriteID
;
566 D(bug("clipboard.device/Command: <UNKNOWN> (%d = 0x%x)\n", ioreq
->io_Command
));
567 ioreq
->io_Error
= IOERR_NOCMD
;
570 } /* switch (ioreq->io_Command) */
572 /* If the quick bit is not set, send the message to the port */
573 if(!(ioreq
->io_Flags
& IOF_QUICK
))
575 ReplyMsg(&ioreq
->io_Message
);
581 /****************************************************************************************/
583 AROS_LH1(LONG
, abortio
,
584 AROS_LHA(struct IORequest
*, ioreq
, A1
),
585 struct ClipboardBase
*, CBBase
, 6, Clipboard
)
589 /* Keep compiler happy */
593 D(bug("clipboard.device/abortio: ioreq 0x%lx\n",ioreq
));
594 /* Nothing to abort */
600 /****************************************************************************************/
602 static void readCb(struct IORequest
*ioreq
, struct ClipboardBase
*CBBase
)
604 /* Is there anything to be read? */
605 if(CBUn
->cu_WriteID
== 0)
607 D(bug("clipboard.device/readcb: nothing to read. setting IOERR_ABORTED as error and releasing semaphore [me=%08lx]\n", FindTask(NULL
)));
608 Close(CBUn
->cu_clipFile
);
609 CBUn
->cu_clipFile
= 0;
610 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
611 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
612 ioClip(ioreq
)->io_Actual
= 0;
613 ioClip(ioreq
)->io_ClipID
= -1;
617 if(ioClip(ioreq
)->io_Offset
>= CBUn
->cu_clipSize
)
619 D(bug("clipboard.device/readCb: detected \"end of file\". Closing clipfile and releasing semaphore [me=%08lx]\n", FindTask(NULL
)));
620 Close(CBUn
->cu_clipFile
);
621 CBUn
->cu_clipFile
= 0;
622 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
623 ioClip(ioreq
)->io_Actual
= 0;
624 ioClip(ioreq
)->io_ClipID
= -1;
628 if (!ioClip(ioreq
)->io_Data
)
630 ioClip(ioreq
)->io_Offset
+= ioClip(ioreq
)->io_Length
;
631 ioClip(ioreq
)->io_Actual
= ioClip(ioreq
)->io_Length
;
635 D(bug("clipboard.device/readCb: Doing read Seek() at offset %d.\n",
636 ioClip(ioreq
)->io_Offset
));
638 Seek(CBUn
->cu_clipFile
, ioClip(ioreq
)->io_Offset
, OFFSET_BEGINNING
);
640 ioClip(ioreq
)->io_Actual
= Read(CBUn
->cu_clipFile
, ioClip(ioreq
)->io_Data
,
641 ioClip(ioreq
)->io_Length
);
643 if (ioClip(ioreq
)->io_Length
>= 4)
645 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x%02x%02x%02x (%c%c%c%c)\n",
646 ioClip(ioreq
)->io_Length
,
647 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
648 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1],
649 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[2],
650 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[3],
651 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
652 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1],
653 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[2],
654 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[3]));
656 else if (ioClip(ioreq
)->io_Length
== 2)
658 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x%02x (%c%c)\n",
659 ioClip(ioreq
)->io_Length
,
660 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
661 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1],
662 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
663 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1]));
665 else if (ioClip(ioreq
)->io_Length
== 1)
667 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x (%c)\n",
668 ioClip(ioreq
)->io_Length
,
669 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
670 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0]));
674 D(bug("clipboard.device/readCb: Did Read nothing: data length = 0 data = 0x%x\n",
675 ioClip(ioreq
)->io_Data
));
678 ioClip(ioreq
)->io_Offset
+= ioClip(ioreq
)->io_Actual
;
680 if (ioClip(ioreq
)->io_Actual
== 0)
682 Close(CBUn
->cu_clipFile
);
683 CBUn
->cu_clipFile
= 0;
684 D(bug("clipboard.device/readCb: io_Actual=0. Calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL
)));
685 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
686 ioClip(ioreq
)->io_ClipID
= -1;
691 /****************************************************************************************/
693 static void writeCb(struct IORequest
*ioreq
, struct ClipboardBase
*CBBase
)
695 D(bug("clipboard.device/writeCb: Trying to get unit lock. Calling ObtainSemaphore [me=%08lx]\n", FindTask(NULL
)));
696 ObtainSemaphore(&CBUn
->cu_UnitLock
);
697 D(bug("clipboard.device/writeCb: Got unit lock.\n"));
699 if(ioClip(ioreq
)->io_ClipID
== 0 ||
700 ioClip(ioreq
)->io_ClipID
== CBUn
->cu_PostID
)
702 /* A new write begins... */
704 CBUn
->cu_clipSize
= 0;
706 if(ioClip(ioreq
)->io_ClipID
== 0)
709 ioClip(ioreq
)->io_ClipID
= CBUn
->cu_WriteID
;
712 /* No more POST writes accepted */
715 if (!(CBUn
->cu_clipFile
= Open(CBUn
->cu_clipFilename
, MODE_NEWFILE
)))
717 D(bug("clipboard.device/writeCb: Opening clipfile in MODE_NEWFILE failed. Releasing Semaphore [me=%08lx]\n", FindTask(NULL
)));
718 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
719 ioClip(ioreq
)->io_Error
= IOERR_ABORTED
;
720 ioClip(ioreq
)->io_Actual
= 0;
721 ioClip(ioreq
)->io_ClipID
= -1;
725 D(bug("clipboard.device/writeCb: Opened file %s\n", CBUn
->cu_clipFilename
));
727 else if(ioClip(ioreq
)->io_ClipID
== CBUn
->cu_WriteID
)
729 D(bug("We already have the semaphore. [me=%08lx]\n", FindTask(NULL
)));
730 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
732 /* Continue the previous write */
736 D(bug("Invalid ClipID. Releasing Semaphore [me=%08lx]\n", FindTask(NULL
)));
737 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
740 ioClip(ioreq
)->io_Error
= IOERR_ABORTED
;
741 ioClip(ioreq
)->io_Actual
= 0;
745 if(ioClip(ioreq
)->io_Offset
> CBUn
->cu_clipSize
)
747 ULONG len
= ioClip(ioreq
)->io_Offset
- CBUn
->cu_clipSize
;
748 ULONG buflen
= len
> WRITEBUFSIZE
? WRITEBUFSIZE
: len
;
749 UBYTE
*buf
= AllocMem(buflen
, MEMF_CLEAR
| MEMF_PUBLIC
);
751 Seek(CBUn
->cu_clipFile
, 0, OFFSET_END
);
757 ULONG size
= len
> WRITEBUFSIZE
? WRITEBUFSIZE
: len
;
759 Write(CBUn
->cu_clipFile
, buf
, size
);
762 FreeMem(buf
, buflen
);
765 Seek(CBUn
->cu_clipFile
, ioClip(ioreq
)->io_Offset
, OFFSET_BEGINNING
);
767 D(bug("clipboard.device/writeCb: Did Seek(), offset = %d\n", ioClip(ioreq
)->io_Offset
));
769 if (ioClip(ioreq
)->io_Length
>= 4)
771 D(bug("clipboard.device/Doing Write: data length = %d data = %02x%02x%02x%02x (%c%c%c%c)\n",
772 ioClip(ioreq
)->io_Length
,
773 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
774 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1],
775 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[2],
776 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[3],
777 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
778 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1],
779 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[2],
780 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[3]));
782 else if (ioClip(ioreq
)->io_Length
== 2)
784 D(bug("clipboard.device/Doing Write: data length = %d data = %02x%02x (%c%c)\n",
785 ioClip(ioreq
)->io_Length
,
786 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
787 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1],
788 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
789 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1]));
791 else if (ioClip(ioreq
)->io_Length
== 1)
793 D(bug("clipboard.device/Doing Write: data length = %d data = %02x (%c)\n",
794 ioClip(ioreq
)->io_Length
,
795 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
796 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0]));
801 D(bug("clipboard.device/Doing Write: Not really!!: data length = 0 data = 0x%x\n",
802 ioClip(ioreq
)->io_Data
));
805 if (ioClip(ioreq
)->io_Length
)
807 ioClip(ioreq
)->io_Actual
= Write(CBUn
->cu_clipFile
, ioClip(ioreq
)->io_Data
, ioClip(ioreq
)->io_Length
);
811 ioClip(ioreq
)->io_Actual
= 0; /* texteditor.mcc does 0-length writes */
814 if ((LONG
)ioClip(ioreq
)->io_Actual
== -1)
816 D(bug("clipboard.device/writeCb: write failed\n"));
817 Close(CBUn
->cu_clipFile
);
818 CBUn
->cu_clipFile
= 0;
819 D(bug("clipboard.device/writeCb: releasing semaphore [me=%08lx]\n", FindTask(NULL
)));
820 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
821 ioClip(ioreq
)->io_Error
= IOERR_ABORTED
;
822 ioClip(ioreq
)->io_Actual
= 0;
823 ioClip(ioreq
)->io_ClipID
= -1;
827 ioClip(ioreq
)->io_Offset
+= ioClip(ioreq
)->io_Actual
;
828 if(ioClip(ioreq
)->io_Offset
> CBUn
->cu_clipSize
)
830 CBUn
->cu_clipSize
= ioClip(ioreq
)->io_Offset
;
835 /****************************************************************************************/
837 static void updateCb(struct IORequest
*ioreq
, struct ClipboardBase
*CBBase
)
839 if(CBUn
->cu_WriteID
!= 0 && CBUn
->cu_WriteID
== ioClip(ioreq
)->io_ClipID
)
841 D(bug("clipboard.device/updateCb: Closing ClipFile\n"));
843 Close(CBUn
->cu_clipFile
);
844 CBUn
->cu_clipFile
= 0;
846 if(CBUn
->cu_PostRequesters
.mlh_Head
->mln_Succ
!= NULL
)
848 /* Wake up first reader */
849 D(bug("clipboard.device/updateCb: Waking up %08lx\n", ((struct PostRequest
*) CBUn
->cu_PostRequesters
.mlh_Head
)->pr_Waiter
));
850 Signal(((struct PostRequest
*) CBUn
->cu_PostRequesters
.mlh_Head
)->pr_Waiter
, SIGF_SINGLE
);
852 D(bug("clipboard.device/updateCb: calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL
)));
854 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
856 D(bug("clipboard.device/updateCb: Calling monitoring hooks\n"));
858 /* Call monitoring hooks. */
859 ObtainSemaphore(&CBBase
->cb_SignalSemaphore
);
862 struct ClipHookMsg chmsg
;
865 chmsg
.chm_ChangeCmd
= CMD_UPDATE
;
866 chmsg
.chm_ClipID
= ioClip(ioreq
)->io_ClipID
;
868 ForeachNode(&CBBase
->cb_HookList
, tnode
)
870 D(bug("Calling hook %08x\n",tnode
));
871 CallHookA((struct Hook
*)tnode
, CBUn
, &chmsg
);
875 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
877 D(bug("clipboard.device/updateCb: Called monitoring hooks\n"));
881 ioClip(ioreq
)->io_Error
= IOERR_ABORTED
;
882 ioClip(ioreq
)->io_Actual
= 0;
885 ioClip(ioreq
)->io_ClipID
= -1;
887 D(bug("clipboard.device/updateCb: end of function [me=%08lx]\n", FindTask(NULL
)));
891 /****************************************************************************************/