2 Copyright © 1998-2006, 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 if (!CBBase
->cb_DosBase
)
147 CBBase
->cb_DosBase
= OpenLibrary("dos.library", 39);
150 if (!CBBase
->cb_DosBase
)
152 ioreq
->io_Error
= IOERR_OPENFAIL
;
153 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
157 if (!CBBase
->cb_UtilityBase
)
159 CBBase
->cb_UtilityBase
= OpenLibrary("utility.library", 39);
162 if (!CBBase
->cb_UtilityBase
)
164 ioreq
->io_Error
= IOERR_OPENFAIL
;
165 CloseLibrary(CBBase
->cb_DosBase
);
166 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
170 /* Set up clipboard directory if we are the first opener */
172 if(CBBase
->cb_ClipDir
== NULL
)
174 D(bug("clipboard.device/Checking for CLIPS:\n"));
176 if (!(tempLock
= Lock("CLIPS:", ACCESS_READ
)))
178 /* CLIPS: is not assigned - revert to ram:Clipboards */
180 D(bug("clipboard.device/CLIPS: not found\n"));
181 D(bug("clipboard.device/Checking for ram:\n"));
183 if (!(tempLock
= Lock("ram:", ACCESS_READ
)))
185 D(bug("clipboard.device/ram: Not found."));
186 ioreq
->io_Error
= IOERR_OPENFAIL
;
190 D(bug("clipboard.device/Found ram:\n"));
191 D(bug("clipboard.device/Checking for ram:clipboards\n"));
193 if (!(tempLock
= Lock("ram:clipboards", ACCESS_READ
)))
195 D(bug("clipboard.device/Not found -- creating ram:Clipboards.\n"));
196 if (!(tempLock
= CreateDir("ram:clipboards")))
198 D(bug("clipboard.device/can't create clipboards file\n"));
199 ioreq
->io_Error
= IOERR_OPENFAIL
;
203 CBBase
->cb_ClipDir
= "ram:clipboards/";
207 D(bug("clipboard.device/Found CLIPS:\n"));
208 CBBase
->cb_ClipDir
= "CLIPS:";
211 /* Release the possible lock we have made */
216 CloseLibrary(CBBase
->cb_DosBase
);
217 CloseLibrary(CBBase
->cb_UtilityBase
);
218 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
223 ForeachNode(&CBBase
->cb_UnitList
, tempNode
)
225 D(bug("clipboard.device/ UnitNode 0x%lx Unit %ld\n",tempNode
,tempNode
->ln_Type
));
226 if(tempNode
->ln_Type
== unitnum
)
228 D(bug("clipboard.device/ found UnitNode\n"));
236 D(bug("clipboard.device/Building unit...\n"));
238 if ((ioreq
->io_Unit
= (struct Unit
*)AllocMem(sizeof(struct ClipboardUnit
),
239 MEMF_CLEAR
| MEMF_PUBLIC
)))
241 CBUn
->cu_Head
.cu_UnitNum
= unitnum
;
242 CBUn
->cu_Head
.cu_Node
.ln_Type
= unitnum
;
244 CBUn
->cu_WriteID
= 0;
246 NEWLIST((struct List
*) &CBUn
->cu_PostRequesters
);
247 InitSemaphore(&CBUn
->cu_UnitLock
);
249 /* Construct clipboard unit filename. */
250 cb_sprintf(CBBase
, CBUn
->cu_clipFilename
, "%s%lu", (ULONG
) CBBase
->cb_ClipDir
,
253 CBUn
->cu_Satisfy
.sm_Unit
= unitnum
;
255 /* Initialization is done, and everything went OK. Add unit to the
256 list of clipboard units. */
257 ADDHEAD((struct List
*)&CBBase
->cb_UnitList
, (struct Node
*)CBUn
);
259 /* Check if there is already a clipboard file for this unit existing.
260 If yes, then set WriteID to 1 so that CMD_READing works, and
261 also setup clipSize */
263 if ((CBUn
->cu_clipFile
= Open(CBUn
->cu_clipFilename
, MODE_OLDFILE
)))
265 if (Seek(CBUn
->cu_clipFile
, 0, OFFSET_END
) != -1)
267 CBUn
->cu_clipSize
= Seek(CBUn
->cu_clipFile
, 0, OFFSET_BEGINNING
);
269 D(bug("clipboard.device/ <%s> clipsize %ld\n",CBUn
->cu_clipFilename
,CBUn
->cu_clipSize
));
270 if (CBUn
->cu_clipSize
!= (ULONG
)-1)
272 D(bug("clipboard.device/ WriteID set\n"));
273 CBUn
->cu_WriteID
= 1;
276 Close(CBUn
->cu_clipFile
);
277 CBUn
->cu_clipFile
= 0;
281 D(bug("clipboard.device/no <%s> file\n",CBUn
->cu_clipFilename
));
286 D(bug("clipboard.device/Couldn't alloc Unit\n"));
287 ioreq
->io_Error
= IOERR_OPENFAIL
;
293 ioreq
->io_Unit
= (struct Unit
*)tempNode
;
296 if ((ioreq
->io_Error
== 0) && CBUn
)
300 else if (CBUn
&& (found
== FALSE
))
302 FreeMem(CBUn
, sizeof(struct ClipboardUnit
));
305 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
310 /****************************************************************************************/
312 static int GM_UNIQUENAME(Close
)
314 LIBBASETYPEPTR CBBase
,
315 struct IORequest
*ioreq
318 D(bug("clipboard.device/close:ioreq 0x%lx\n",ioreq
));
320 /* Let any following attemps to use the device crash hard. */
321 ioreq
->io_Device
= (struct Device
*)-1;
323 ObtainSemaphore(&CBBase
->cb_SignalSemaphore
);
327 D(bug("clipboard.device/close: unitcnt %ld\n",CBUn
->cu_OpenCnt
));
329 if(CBUn
->cu_OpenCnt
== 0)
331 D(bug("clipboard.device/close: removeunit\n",ioreq
));
332 REMOVE((struct Node
*)ioreq
->io_Unit
);
333 FreeMem(ioreq
->io_Unit
, sizeof(struct ClipboardUnit
));
335 /* Let any following attemps to use the device crash hard. */
336 ioreq
->io_Unit
= (struct Unit
*) -1;
339 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
344 /****************************************************************************************/
346 static int GM_UNIQUENAME(Expunge
)(LIBBASETYPEPTR CBBase
)
348 D(bug("clipboard.device/expunge:\n"));
350 CloseLibrary(CBBase
->cb_DosBase
);
351 CloseLibrary(CBBase
->cb_UtilityBase
);
356 /****************************************************************************************/
358 ADD2INITLIB(GM_UNIQUENAME(Init
), 0)
359 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge
), 0)
360 ADD2OPENDEV(GM_UNIQUENAME(Open
), 0)
361 ADD2CLOSEDEV(GM_UNIQUENAME(Close
), 0)
363 /****************************************************************************************/
365 AROS_LH1(void, beginio
,
366 AROS_LHA(struct IORequest
*, ioreq
, A1
),
367 struct ClipboardBase
*, CBBase
, 5, Clipboard
)
373 switch (ioreq
->io_Command
)
376 case NSCMD_DEVICEQUERY
:
377 if(ioClip(ioreq
)->io_Length
< ((LONG
)OFFSET(NSDeviceQueryResult
, SupportedCommands
)) + sizeof(UWORD
*))
379 ioreq
->io_Error
= IOERR_BADLENGTH
;
383 struct NSDeviceQueryResult
*d
;
385 d
= (struct NSDeviceQueryResult
*)ioClip(ioreq
)->io_Data
;
387 d
->DevQueryFormat
= 0;
388 d
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
389 d
->DeviceType
= NSDEVTYPE_CLIPBOARD
;
390 d
->DeviceSubType
= 0;
391 d
->SupportedCommands
= (UWORD
*)SupportedCommands
;
393 ioClip(ioreq
)->io_Actual
= sizeof(struct NSDeviceQueryResult
);
400 D(bug("clipboard.device/Command: CBD_CHANGEHOOK\n"));
402 ObtainSemaphore(&CBBase
->cb_SignalSemaphore
);
404 /* io_Length is used as a means of specifying if the hook
405 should be added or removed. */
406 switch(ioClip(ioreq
)->io_Length
)
409 REMOVE((struct Node
*)(ioClip(ioreq
)->io_Data
));
413 ADDHEAD((struct List
*)&CBBase
->cb_HookList
,
414 (struct Node
*)ioClip(ioreq
)->io_Data
);
418 ioreq
->io_Error
= IOERR_BADLENGTH
;
421 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
426 D(bug("clipboard.device/Command: CMD_WRITE\n"));
428 writeCb(ioreq
, CBBase
);
433 D(bug("clipboard.device/Command: CMD_READ\n"));
435 /* Get new ID if this is the beginning of a read operation */
436 if(ioClip(ioreq
)->io_ClipID
== 0)
438 D(bug("clipboard.device/CMD_READ: Trying to get unit lock. Calling ObtainSemaphore [me=%08lx].\n", FindTask(NULL
)));
440 ObtainSemaphore(&CBUn
->cu_UnitLock
);
442 D(bug("clipboard.device/CMD_READ: Got unit lock.\n"));
444 /* If the last write was actually a POST, we must tell
445 the POSTer to WRITE the clip immediately, and we
446 will wait until he have done so. Then we check
447 again in case somebody managed to sneek in a
448 CBD_POST after the CMD_UPDATE. */
450 while(CBUn
->cu_WriteID
!= 0 &&
451 CBUn
->cu_WriteID
== CBUn
->cu_PostID
)
453 struct PostRequest pr
= {
458 /* Make sure we are signalled. */
459 ADDTAIL((struct List
*) &CBUn
->cu_PostRequesters
, (struct Node
*) &pr
);
461 /* A poster reading will deadlock that process
462 * until somebody else writes to the
463 * clipboard. AmigaOS behaves exactly the same so
464 * it's ok. It's just plain stupid anyway. */
466 if (CBUn
->cu_PostPort
)
468 D(bug("clipboard.device/Command: CMD_READ..notify PostPort 0x%lx\n", CBUn
->cu_PostPort
));
470 CBUn
->cu_Satisfy
.sm_ClipID
= CBUn
->cu_PostID
;
471 PutMsg(CBUn
->cu_PostPort
, (struct Message
*)&CBUn
->cu_Satisfy
);
472 CBUn
->cu_PostPort
= NULL
;
476 D(bug("clipboard.device/Command: no PostPort [me=%08lx]\n", FindTask(NULL
)));
480 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
481 SetSignal(0, SIGF_SINGLE
);
484 D(bug("Got SIGF_SINGLE [me=%08lx]\n",FindTask(NULL
)));
485 ObtainSemaphore(&CBUn
->cu_UnitLock
);
486 D(bug("Got semaphore[me=%08lx]\n",FindTask(NULL
)));
488 if(pr
.pr_Link
.mln_Succ
->mln_Succ
!= NULL
)
490 /* Wake up next reader */
491 Signal(((struct PostRequest
*) pr
.pr_Link
.mln_Succ
)->pr_Waiter
, SIGF_SINGLE
);
494 Remove((struct Node
*) &pr
);
498 ioClip(ioreq
)->io_ClipID
= CBUn
->cu_ReadID
;
500 CBUn
->cu_clipFile
= Open(CBUn
->cu_clipFilename
, MODE_OLDFILE
);
502 if(!CBUn
->cu_clipFile
)
504 D(bug("clipboard.device/CMD_READ: No clip file. Calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL
)));
505 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
506 ioClip(ioreq
)->io_ClipID
= -1;
507 ioClip(ioreq
)->io_Actual
= 0;
508 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
512 else if(ioClip(ioreq
)->io_ClipID
!= CBUn
->cu_ReadID
)
514 D(bug("clipboard.device/CMD_READ: Invalid clip id.\n"));
515 ioClip(ioreq
)->io_Actual
= 0;
516 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
520 readCb(ioreq
, CBBase
);
526 D(bug("clipboard.device/Command: CMD_UPDATE\n"));
528 updateCb(ioreq
, CBBase
);
533 D(bug("clipboard.device/Command: CBD_POST [me=%08lx]\n", FindTask(NULL
)));
534 ObtainSemaphore(&CBUn
->cu_UnitLock
);
537 CBUn
->cu_PostID
= CBUn
->cu_WriteID
;
538 CBUn
->cu_PostPort
= (struct MsgPort
*)ioClip(ioreq
)->io_Data
;
540 ioClip(ioreq
)->io_ClipID
= CBUn
->cu_PostID
;
542 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
544 D(bug("clipboard.device/CBD_POST: Calling monitoring hooks\n"));
546 /* Call monitoring hooks. */
547 ObtainSemaphore(&CBBase
->cb_SignalSemaphore
);
550 struct ClipHookMsg chmsg
;
553 chmsg
.chm_ChangeCmd
= CBD_POST
;
554 chmsg
.chm_ClipID
= CBUn
->cu_PostID
;
556 ForeachNode(&CBBase
->cb_HookList
, tnode
)
558 D(bug("Calling hook %08x\n",tnode
));
559 CallHookA((struct Hook
*)tnode
, CBUn
, &chmsg
);
563 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
565 D(bug("clipboard.device/CBD_POST: Called monitoring hooks\n"));
568 // This does not seem to be robust enough; it can lead to
569 // a ping-pong effect. Never mind then.
571 ObtainSemaphore(&CBUn
->cu_UnitLock
);
573 if(!IsListEmpty((struct List
*) &CBUn
->cu_PostRequesters
))
575 /* Normally, this can never happen. However, if an app
576 deadlocked by posting and then reading, try to make
577 this CBD_POST turn into a CMD_WRITE immediately. */
579 D(bug("clipboard.device/Command: CMD_POST..notify PostPort 0x%lx\n", CBUn
->cu_PostPort
));
581 CBUn
->cu_Satisfy
.sm_ClipID
= CBUn
->cu_PostID
;
582 PutMsg(CBUn
->cu_PostPort
, (struct Message
*)&CBUn
->cu_Satisfy
);
583 CBUn
->cu_PostPort
= NULL
;
586 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
591 case CBD_CURRENTREADID
:
592 D(bug("clipboard.device/Command: CBD_CURRENTREADID\n"));
593 ioClip(ioreq
)->io_ClipID
= CBUn
->cu_WriteID
;
594 /* NOTE: NOT A BUG! Was PostID. Note that AmigaOS really has a
595 ReadID counter that is *almost* always the same as WriteID. */
599 case CBD_CURRENTWRITEID
:
600 D(bug("clipboard.device/Command: CBD_CURRENTWRITEID\n"));
601 ioClip(ioreq
)->io_ClipID
= CBUn
->cu_WriteID
;
606 D(bug("clipboard.device/Command: <UNKNOWN> (%d = 0x%x)\n", ioreq
->io_Command
));
607 ioreq
->io_Error
= IOERR_NOCMD
;
610 } /* switch (ioreq->io_Command) */
612 /* If the quick bit is not set, send the message to the port */
613 if(!(ioreq
->io_Flags
& IOF_QUICK
))
615 ReplyMsg(&ioreq
->io_Message
);
621 /****************************************************************************************/
623 AROS_LH1(LONG
, abortio
,
624 AROS_LHA(struct IORequest
*, ioreq
, A1
),
625 struct ClipboardBase
*, CBBase
, 6, Clipboard
)
629 /* Keep compiler happy */
633 D(bug("clipboard.device/abortio: ioreq 0x%lx\n",ioreq
));
634 /* Nothing to abort */
640 /****************************************************************************************/
642 static void readCb(struct IORequest
*ioreq
, struct ClipboardBase
*CBBase
)
644 /* Is there anything to be read? */
645 if(CBUn
->cu_WriteID
== 0)
647 D(bug("clipboard.device/readcb: nothing to read. setting IOERR_ABORTED as error and releasing semaphore [me=%08lx]\n", FindTask(NULL
)));
648 Close(CBUn
->cu_clipFile
);
649 CBUn
->cu_clipFile
= 0;
650 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
651 // ioClip(ioreq)->io_Error = IOERR_ABORTED;
652 ioClip(ioreq
)->io_Actual
= 0;
653 ioClip(ioreq
)->io_ClipID
= -1;
657 if(ioClip(ioreq
)->io_Offset
>= CBUn
->cu_clipSize
)
659 D(bug("clipboard.device/readCb: detected \"end of file\". Closing clipfile and releasing semaphore [me=%08lx]\n", FindTask(NULL
)));
660 Close(CBUn
->cu_clipFile
);
661 CBUn
->cu_clipFile
= 0;
662 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
663 ioClip(ioreq
)->io_Actual
= 0;
664 ioClip(ioreq
)->io_ClipID
= -1;
668 if (!ioClip(ioreq
)->io_Data
)
670 ioClip(ioreq
)->io_Offset
+= ioClip(ioreq
)->io_Length
;
671 ioClip(ioreq
)->io_Actual
= ioClip(ioreq
)->io_Length
;
675 D(bug("clipboard.device/readCb: Doing read Seek() at offset %d.\n",
676 ioClip(ioreq
)->io_Offset
));
678 Seek(CBUn
->cu_clipFile
, ioClip(ioreq
)->io_Offset
, OFFSET_BEGINNING
);
680 ioClip(ioreq
)->io_Actual
= Read(CBUn
->cu_clipFile
, ioClip(ioreq
)->io_Data
,
681 ioClip(ioreq
)->io_Length
);
683 if (ioClip(ioreq
)->io_Length
>= 4)
685 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x%02x%02x%02x (%c%c%c%c)\n",
686 ioClip(ioreq
)->io_Length
,
687 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
688 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1],
689 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[2],
690 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[3],
691 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
692 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1],
693 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[2],
694 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[3]));
696 else if (ioClip(ioreq
)->io_Length
== 2)
698 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x%02x (%c%c)\n",
699 ioClip(ioreq
)->io_Length
,
700 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
701 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1],
702 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
703 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1]));
705 else if (ioClip(ioreq
)->io_Length
== 1)
707 D(bug("clipboard.device/readCb: Did Read: data length = %d data = %02x (%c)\n",
708 ioClip(ioreq
)->io_Length
,
709 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
710 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0]));
714 D(bug("clipboard.device/readCb: Did Read nothing: data length = 0 data = 0x%x\n",
715 ioClip(ioreq
)->io_Data
));
718 ioClip(ioreq
)->io_Offset
+= ioClip(ioreq
)->io_Actual
;
720 if (ioClip(ioreq
)->io_Actual
== 0)
722 Close(CBUn
->cu_clipFile
);
723 CBUn
->cu_clipFile
= 0;
724 D(bug("clipboard.device/readCb: io_Actual=0. Calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL
)));
725 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
726 ioClip(ioreq
)->io_ClipID
= -1;
731 /****************************************************************************************/
733 static void writeCb(struct IORequest
*ioreq
, struct ClipboardBase
*CBBase
)
735 D(bug("clipboard.device/writeCb: Trying to get unit lock. Calling ObtainSemaphore [me=%08lx]\n", FindTask(NULL
)));
736 ObtainSemaphore(&CBUn
->cu_UnitLock
);
737 D(bug("clipboard.device/writeCb: Got unit lock.\n"));
739 if(ioClip(ioreq
)->io_ClipID
== 0 ||
740 ioClip(ioreq
)->io_ClipID
== CBUn
->cu_PostID
)
742 /* A new write begins... */
744 CBUn
->cu_clipSize
= 0;
746 if(ioClip(ioreq
)->io_ClipID
== 0)
749 ioClip(ioreq
)->io_ClipID
= CBUn
->cu_WriteID
;
752 /* No more POST writes accepted */
755 if (!(CBUn
->cu_clipFile
= Open(CBUn
->cu_clipFilename
, MODE_NEWFILE
)))
757 D(bug("clipboard.device/writeCb: Opening clipfile in MODE_NEWFILE failed. Releasing Semaphore [me=%08lx]\n", FindTask(NULL
)));
758 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
759 ioClip(ioreq
)->io_Error
= IOERR_ABORTED
;
760 ioClip(ioreq
)->io_Actual
= 0;
761 ioClip(ioreq
)->io_ClipID
= -1;
765 D(bug("clipboard.device/writeCb: Opened file %s\n", CBUn
->cu_clipFilename
));
767 else if(ioClip(ioreq
)->io_ClipID
== CBUn
->cu_WriteID
)
769 D(bug("We already have the semaphore. [me=%08lx]\n", FindTask(NULL
)));
770 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
772 /* Continue the previous write */
776 D(bug("Invalid ClipID. Releasing Semaphore [me=%08lx]\n", FindTask(NULL
)));
777 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
780 ioClip(ioreq
)->io_Error
= IOERR_ABORTED
;
781 ioClip(ioreq
)->io_Actual
= 0;
785 if(ioClip(ioreq
)->io_Offset
> CBUn
->cu_clipSize
)
787 ULONG len
= ioClip(ioreq
)->io_Offset
- CBUn
->cu_clipSize
;
788 ULONG buflen
= len
> WRITEBUFSIZE
? WRITEBUFSIZE
: len
;
789 UBYTE
*buf
= AllocMem(buflen
, MEMF_CLEAR
| MEMF_PUBLIC
);
791 Seek(CBUn
->cu_clipFile
, 0, OFFSET_END
);
797 ULONG size
= len
> WRITEBUFSIZE
? WRITEBUFSIZE
: len
;
799 Write(CBUn
->cu_clipFile
, buf
, size
);
802 FreeMem(buf
, buflen
);
805 Seek(CBUn
->cu_clipFile
, ioClip(ioreq
)->io_Offset
, OFFSET_BEGINNING
);
807 D(bug("clipboard.device/writeCb: Did Seek(), offset = %d\n", ioClip(ioreq
)->io_Offset
));
809 if (ioClip(ioreq
)->io_Length
>= 4)
811 D(bug("clipboard.device/Doing Write: data length = %d data = %02x%02x%02x%02x (%c%c%c%c)\n",
812 ioClip(ioreq
)->io_Length
,
813 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
814 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1],
815 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[2],
816 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[3],
817 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
818 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1],
819 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[2],
820 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[3]));
822 else if (ioClip(ioreq
)->io_Length
== 2)
824 D(bug("clipboard.device/Doing Write: data length = %d data = %02x%02x (%c%c)\n",
825 ioClip(ioreq
)->io_Length
,
826 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
827 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1],
828 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
829 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[1]));
831 else if (ioClip(ioreq
)->io_Length
== 1)
833 D(bug("clipboard.device/Doing Write: data length = %d data = %02x (%c)\n",
834 ioClip(ioreq
)->io_Length
,
835 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0],
836 ((UBYTE
*)ioClip(ioreq
)->io_Data
)[0]));
841 D(bug("clipboard.device/Doing Write: Not really!!: data length = 0 data = 0x%x\n",
842 ioClip(ioreq
)->io_Data
));
845 if (ioClip(ioreq
)->io_Length
)
847 ioClip(ioreq
)->io_Actual
= Write(CBUn
->cu_clipFile
, ioClip(ioreq
)->io_Data
, ioClip(ioreq
)->io_Length
);
851 ioClip(ioreq
)->io_Actual
= 0; /* texteditor.mcc does 0-length writes */
854 if ((LONG
)ioClip(ioreq
)->io_Actual
== -1)
856 D(bug("clipboard.device/writeCb: write failed\n"));
857 Close(CBUn
->cu_clipFile
);
858 CBUn
->cu_clipFile
= 0;
859 D(bug("clipboard.device/writeCb: releasing semaphore [me=%08lx]\n", FindTask(NULL
)));
860 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
861 ioClip(ioreq
)->io_Error
= IOERR_ABORTED
;
862 ioClip(ioreq
)->io_Actual
= 0;
863 ioClip(ioreq
)->io_ClipID
= -1;
867 ioClip(ioreq
)->io_Offset
+= ioClip(ioreq
)->io_Actual
;
868 if(ioClip(ioreq
)->io_Offset
> CBUn
->cu_clipSize
)
870 CBUn
->cu_clipSize
= ioClip(ioreq
)->io_Offset
;
875 /****************************************************************************************/
877 static void updateCb(struct IORequest
*ioreq
, struct ClipboardBase
*CBBase
)
879 if(CBUn
->cu_WriteID
!= 0 && CBUn
->cu_WriteID
== ioClip(ioreq
)->io_ClipID
)
881 D(bug("clipboard.device/updateCb: Closing ClipFile\n"));
883 Close(CBUn
->cu_clipFile
);
884 CBUn
->cu_clipFile
= 0;
886 if(CBUn
->cu_PostRequesters
.mlh_Head
->mln_Succ
!= NULL
)
888 /* Wake up first reader */
889 D(bug("clipboard.device/updateCb: Waking up %08lx\n", ((struct PostRequest
*) CBUn
->cu_PostRequesters
.mlh_Head
)->pr_Waiter
));
890 Signal(((struct PostRequest
*) CBUn
->cu_PostRequesters
.mlh_Head
)->pr_Waiter
, SIGF_SINGLE
);
892 D(bug("clipboard.device/updateCb: calling ReleaseSemaphore [me=%08lx]\n", FindTask(NULL
)));
894 ReleaseSemaphore(&CBUn
->cu_UnitLock
);
896 D(bug("clipboard.device/updateCb: Calling monitoring hooks\n"));
898 /* Call monitoring hooks. */
899 ObtainSemaphore(&CBBase
->cb_SignalSemaphore
);
902 struct ClipHookMsg chmsg
;
905 chmsg
.chm_ChangeCmd
= CMD_UPDATE
;
906 chmsg
.chm_ClipID
= ioClip(ioreq
)->io_ClipID
;
908 ForeachNode(&CBBase
->cb_HookList
, tnode
)
910 D(bug("Calling hook %08x\n",tnode
));
911 CallHookA((struct Hook
*)tnode
, CBUn
, &chmsg
);
915 ReleaseSemaphore(&CBBase
->cb_SignalSemaphore
);
917 D(bug("clipboard.device/updateCb: Called monitoring hooks\n"));
921 ioClip(ioreq
)->io_Error
= IOERR_ABORTED
;
922 ioClip(ioreq
)->io_Actual
= 0;
925 ioClip(ioreq
)->io_ClipID
= -1;
927 D(bug("clipboard.device/updateCb: end of function [me=%08lx]\n", FindTask(NULL
)));
931 /****************************************************************************************/