revert between 56095 -> 55830 in arch
[AROS.git] / workbench / libs / commodities / commodities_inputhandler.c
bloba7f7922a444fe6412a79e1cfe1c4438975518595
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Commodities input handler
6 Lang: English
7 */
9 /* INTERNALS
11 * Currently, there is no protection against stupid users. If you, for
12 instance, install a broker and attach a custom object to it, and this
13 custom object's function is to Route the messages to the broker, there
14 will be a deadlock, as the message list will never get empty.
15 I have no GOOD solution for this, and therefore nothing to prevent
16 this type of deadlock is implemented. One way could be to have a counter
17 (in every message) that says how many times a message has been routed
18 and if this counter reaches MAGICAL_VALUE the message is Disposed of.
19 The above should then perhaps be accompanied by a new COMMAND,
20 CXCMD_CYCLE that tells (at least Exchange) that something isn't quite
21 right.
23 * CX_TYPEFILTER isn't documented anywhere (and it's obsolete) meaning
24 that the action done in case of a typefilter is not known to be the
25 correct one.
28 HISTORY
30 ??.08.97 SDuvan Implemented
31 16.08.99 Working version
34 /***************************************************************************/
36 #include "cxintern.h"
37 #include <proto/exec.h>
38 #include <proto/commodities.h>
39 #include <exec/lists.h>
40 #include <exec/memory.h>
41 #include <aros/asmcall.h>
42 #include <stddef.h>
43 #include <string.h>
45 #define DEBUG_CXTREE(x) ;//if ((msg->cxm_Data->ie_Class == IECLASS_RAWMOUSE) && (msg->cxm_Data->ie_Code != 255)) { x; }
46 #define DEBUG_TRANSFUNC(x) ;
47 #define DEBUG_SENDFUNC(x) ;
48 #define DEBUG_COPYIEVENT(x) x;
50 #define SUPERDEBUG 0
51 #define DEBUG 0
52 #include <aros/debug.h>
54 static void ProduceEvent(CxMsg *, struct CommoditiesBase *CxBase);
55 static void DebugFunc(CxMsg *, CxObj *, struct CommoditiesBase *CxBase);
56 static void TransFunc(CxMsg *, CxObj *, struct CommoditiesBase *CxBase);
57 static void SendFunc(CxMsg *, CxObj *, struct CommoditiesBase *CxBase);
58 BOOL CopyInputEvent(struct InputEvent *from, struct InputEvent *to, struct CommoditiesBase *CxBase);
60 #ifdef __mc68000
61 extern void cx_Thunk(void);
62 asm (
63 ".global cx_Thunk\n"
64 "cx_Thunk:\n"
65 "movem.l %a0-%a1,%sp@-\n"
66 "jsr.l %a2@\n"
67 "addq.l #8,%sp\n"
68 "rts\n"
70 #endif
72 AROS_UFH2(struct InputEvent *, CxTree,
73 AROS_UFHA(struct InputEvent * , events , A0),
74 AROS_UFHA(struct CommoditiesBase *, CxBase , A6))
76 AROS_USERFUNC_INIT
78 CxObj *co;
79 CxMsg *tempMsg, *msg;
80 struct Node *node, *succ;
82 if (events == NULL)
84 return NULL;
87 ObtainSemaphore(&CxBase->cx_SignalSemaphore);
89 if (IsListEmpty(&CxBase->cx_BrokerList))
91 ReleaseSemaphore(&CxBase->cx_SignalSemaphore);
93 return events;
96 /* Take care of the processed input events */
97 ForeachNodeSafe(&CxBase->cx_GeneratedInputEvents, node, succ)
99 struct GeneratedInputEvent *tempEvent;
101 tempEvent = (struct GeneratedInputEvent *)(((UBYTE *)node) - offsetof(struct GeneratedInputEvent, node));
102 FreeCxStructure(tempEvent, CX_INPUTEVENT, (struct Library *)CxBase);
105 CxBase->cx_IEvents = NULL;
106 CxBase->cx_EventExtra = &CxBase->cx_IEvents;
107 NEWLIST(&CxBase->cx_GeneratedInputEvents);
109 /* Free all the replied messages */
110 while ((tempMsg = (CxMsg *)GetMsg(&CxBase->cx_MsgPort)) != NULL)
112 FreeCxStructure(tempMsg, CX_MESSAGE, (struct Library *)CxBase);
115 #if SUPERDEBUG
117 CxObj *node;
119 kprintf("List of brokers:\n");
121 ForeachNode(&CxBase->cx_BrokerList, node)
123 if (CXOBJType(node) == CX_BROKER)
125 kprintf("B: %s\n", node->co_Ext.co_BExt->bext_Name);
127 else
129 kprintf("Something else\n");
133 #endif
135 /* Route all messages to the first broker */
137 co = (CxObj *)GetHead(&CxBase->cx_BrokerList);
139 #if SUPERDEBUG
140 kprintf("Initial broker: %s\n", co->co_Ext.co_BExt->bext_Name);
141 #endif
143 ForeachNode(&CxBase->cx_MessageList, tempMsg)
145 ROUTECxMsg(tempMsg, co);
148 AddIEvents(events); /* Add the new events (incapsulated in commodtity
149 messages) to the message list. */
151 /***************************************************************************/
153 /* Process the new events */
155 while ((msg = (CxMsg *)GetHead(&CxBase->cx_MessageList)) != NULL)
157 co = msg->cxm_Routing;
159 DEBUG_CXTREE(dprintf("CxTree: Msg %p Object %p\n", msg, co));
161 while (co == NULL && msg->cxm_Level != 0)
163 // kprintf("Next level %i\n", msg->cxm_Level - 1);
165 msg->cxm_Level--;
166 co = msg->cxm_retObj[msg->cxm_Level];
167 co = (CxObj *)GetSucc(&co->co_Node);
169 // kprintf("Found return object %p\n", co);
171 // if (CXOBJType(co) == CX_BROKER)
172 // {
173 // kprintf("Returnobj (broker) = %s\n",
174 // co->co_Ext.co_BExt->bext_Name);
175 // }
178 /* If there are no more objects that shall process the event, we
179 link it in to the list of ready input events */
181 if (co == NULL)
183 ProduceEvent(msg, CxBase);
184 continue;
187 #if DEBUG
188 DEBUG_CXTREE(
190 if(CXOBJType(co) == CX_BROKER)
191 kprintf("Broker: %s\n", co->co_Ext.co_BExt->bext_Name);
193 if(co->co_Node.ln_Succ != NULL &&
194 co->co_Node.ln_Succ->ln_Type == CX_BROKER)
195 kprintf("Routing to next broker %s (this broker=%s) %p\n",
196 ((CxObj *)(co->co_Node.ln_Succ))->co_Ext.co_BExt->bext_Name,
197 co->co_Ext.co_BExt->bext_Name,
198 co);
200 #endif
202 /* Route the message to the next object */
204 ROUTECxMsg(msg, (CxObj *)GetSucc(&co->co_Node));
206 if (!(co->co_Flags & COF_ACTIVE))
208 continue;
211 DEBUG_CXTREE(dprintf("CxTree: Object %p Type %d\n", co, CXOBJType(co)));
213 switch (CXOBJType(co))
215 case CX_INVALID:
216 DEBUG_CXTREE(dprintf("CxTree: CX_INVALID\n"));
217 break;
219 case CX_FILTER:
220 DEBUG_CXTREE(dprintf("CxTree: CX_FILTER\n"));
222 DEBUG_CXTREE(dprintf("CxTree: Filter 0x%lx\n",
223 msg->cxm_Type));
225 if ((co->co_Error & COERR_BADFILTER))
227 DEBUG_CXTREE(dprintf("CxTree: bad filter!\n"));
228 break;
231 if (msg->cxm_Type == CXM_IEVENT)
233 DEBUG_CXTREE(dprintf("CxTree: Data 0x%lx FilterIX 0x%lx\n",
234 msg->cxm_Data,
235 co->co_Ext.co_FilterIX));
236 if (MatchIX(msg->cxm_Data, co->co_Ext.co_FilterIX) != 0)
238 DEBUG_CXTREE(dprintf("CxTree: filter matched\n"));
239 DivertCxMsg(msg, co, co);
241 else
243 DEBUG_CXTREE(dprintf("CxTree: filter not matched\n"));
246 else
248 DEBUG_CXTREE(dprintf("CxTree: no CXM_EVENT\n"));
250 break;
252 case CX_TYPEFILTER:
253 DEBUG_CXTREE(dprintf("CxTree: CX_TYPEFILTER\n"));
254 if ((msg->cxm_Type & co->co_Ext.co_TypeFilter) != 0)
256 DEBUG_CXTREE(dprintf("CxTree: hit\n"));
257 DivertCxMsg(msg, co, co);
259 break;
261 case CX_SEND:
262 DEBUG_CXTREE(dprintf("CxTree: CX_SEND\n"));
263 SendFunc(msg, co, CxBase);
264 break;
266 case CX_SIGNAL:
267 DEBUG_CXTREE(dprintf("CxTree: CX_SIGNAL Task 0x%lx <%s>\n",
268 co->co_Ext.co_SignalExt->sixt_Task,
269 co->co_Ext.co_SignalExt->sixt_Task->tc_Node.ln_Name));
270 Signal(co->co_Ext.co_SignalExt->sixt_Task,
271 1 << co->co_Ext.co_SignalExt->sixt_SigBit);
272 break;
274 case CX_TRANSLATE:
275 DEBUG_CXTREE(dprintf("CxTree: CX_TRANSLATE\n"));
276 TransFunc(msg, co, CxBase);
277 break;
279 case CX_BROKER:
280 DEBUG_CXTREE(dprintf("CxTree: CX_BROKER\n"));
281 DivertCxMsg(msg, co, co);
282 break;
284 case CX_DEBUG:
285 DEBUG_CXTREE(dprintf("CxTree: CX_DEBUG\n"));
286 DebugFunc(msg, co, CxBase);
287 break;
289 case CX_CUSTOM:
290 DEBUG_CXTREE(dprintf("CxTree: CX_CUSTOM\n"));
291 msg->cxm_ID = co->co_Ext.co_CustomExt->cext_ID;
293 DEBUG_CXTREE(dprintf("CxTree: Action 0x%lx\n",
294 co->co_Ext.co_CustomExt->cext_Action));
295 /* Action shouldn't be NULL, but well, sometimes it is...
297 if (co->co_Ext.co_CustomExt->cext_Action)
299 #ifdef __mc68000
300 /* The autodocs suggest the arguments should be passed on the stack.
301 * But they were also in a0/a1 and some things seem to rely on that.
302 * Let's also pass CxBase in a6 just in case.
304 * All other architectures (should) be using the stack.
306 AROS_UFC4NR(void, cx_Thunk,
307 AROS_UFCA(CxMsg*, msg, A0),
308 AROS_UFCA(CxObj*, co, A1),
309 AROS_UFCA(APTR, co->co_Ext.co_CustomExt->cext_Action, A2),
310 AROS_UFCA(struct CommoditiesBase *, CxBase, A6));
311 #else
312 #ifdef __MORPHOS__
313 REG_A7 -= 8;
314 *(CxMsg**)REG_A7 = msg;
315 *(CxObj**)(REG_A7 + 4) = co;
316 #endif
317 AROS_UFC3(void, co->co_Ext.co_CustomExt->cext_Action,
318 AROS_UFCA(CxMsg*, msg, A0),
319 AROS_UFCA(CxObj*, co, A1),
320 AROS_UFCA(struct CommoditiesBase *, CxBase, A6));
321 #ifdef __MORPHOS__
322 REG_A7 += 8;
323 #endif
324 #endif
326 break;
328 case CX_ZERO:
329 DEBUG_CXTREE(dprintf("CxTree: CX_ZERO\n"));
330 ProduceEvent(msg, CxBase);
331 break;
334 DEBUG_CXTREE(dprintf("CxTree: done\n"));
337 ReleaseSemaphore(&CxBase->cx_SignalSemaphore);
339 return CxBase->cx_IEvents;
341 AROS_USERFUNC_EXIT
345 static void ProduceEvent(CxMsg *msg, struct CommoditiesBase *CxBase)
347 struct GeneratedInputEvent *temp;
349 if ((temp = (struct GeneratedInputEvent *)AllocCxStructure(CX_INPUTEVENT, 0,
350 (struct Library *)CxBase)) != NULL)
352 if (!CopyInputEvent(msg->cxm_Data, &temp->ie, CxBase))
354 DEBUG_COPYIEVENT(dprintf("ProduceEvent: CopyInputEvent() failed!\n"));
357 /* Put the input event last in the ready list and update bookkeeping */
358 temp->ie.ie_NextEvent = NULL;
360 *(CxBase->cx_EventExtra) = &temp->ie;
361 CxBase->cx_EventExtra = &temp->ie.ie_NextEvent;
363 AddTail((struct List *)&CxBase->cx_GeneratedInputEvents,
364 (struct Node *)&temp->node);
367 DisposeCxMsg(msg);
371 static void SendFunc(CxMsg *msg, CxObj *co, struct CommoditiesBase *CxBase)
373 CxMsg *tempMsg;
374 struct InputEvent *saveIE; /* To save the InputEvent pointer
375 from being destroyed by CopyMem() */
377 DEBUG_SENDFUNC(dprintf("SendFunc: msg %p co %p MsgPort %p ID 0x%lx\n",
378 msg, co, co->co_Ext.co_SendExt->sext_MsgPort, co->co_Ext.co_SendExt->sext_ID));
380 if (co->co_Ext.co_SendExt->sext_MsgPort == NULL)
382 return;
385 tempMsg = (CxMsg *)AllocCxStructure(CX_MESSAGE, CXM_DOUBLE,
386 (struct Library *)CxBase);
388 if (tempMsg == NULL)
390 DEBUG_SENDFUNC(dprintf("SendFunc: failed!\n"));
391 return;
394 saveIE = tempMsg->cxm_Data;
395 CopyMem(msg, tempMsg, sizeof(CxMsg));
396 tempMsg->cxm_Data = saveIE;
398 if (!CopyInputEvent(msg->cxm_Data, tempMsg->cxm_Data, CxBase))
400 DEBUG_COPYIEVENT(dprintf("SendFunc: CopyInputEvent() failed!\n"));
403 tempMsg->cxm_ID = co->co_Ext.co_SendExt->sext_ID;
405 PutMsg(co->co_Ext.co_SendExt->sext_MsgPort, (struct Message *)tempMsg);
409 static void TransFunc(CxMsg *msg, CxObj *co, struct CommoditiesBase *CxBase)
411 struct InputEvent *event;
412 CxMsg *msg2;
414 DEBUG_TRANSFUNC(dprintf("TransFunc: msg %p co %p ie %p\n",
415 msg, co, co->co_Ext.co_IE));
417 if (co->co_Ext.co_IE != NULL)
419 event = co->co_Ext.co_IE;
423 struct InputEvent *saveIE; /* To save the InputEvent pointer
424 from being destroyed by CopyMem() */
426 DEBUG_TRANSFUNC(dprintf("TransFunc: Generate class %d code 0x%x\n",
427 event->ie_Class, event->ie_Code));
429 if ((msg2 = (CxMsg *)AllocCxStructure(CX_MESSAGE, CXM_DOUBLE,
430 (struct Library *)CxBase)) == NULL)
432 DEBUG_TRANSFUNC(dprintf("TransFunc: failed!\n"));
433 break;
436 saveIE = msg2->cxm_Data;
437 CopyMem(msg, msg2, sizeof(CxMsg));
438 msg2->cxm_Data = saveIE;
440 /* Don't care about errors for now */
441 if (!CopyInputEvent(event, msg2->cxm_Data, CxBase))
443 DEBUG_COPYIEVENT(dprintf("TransFunc: CopyInputEvent() failed!\n"));
446 AddHead(&CxBase->cx_MessageList, (struct Node *)msg2);
448 } while ((event = event->ie_NextEvent) != NULL);
451 DisposeCxMsg(msg);
455 static void DebugFunc(CxMsg *msg, CxObj *co, struct CommoditiesBase *CxBase)
457 kprintf("\n----\nDEBUG NODE: %lx, ID: %lx\n"
458 "\tCxMsg: %lx, type: %x, data %lx destination %lx\n",
459 co, co->co_Ext.co_DebugID, msg->cxm_Routing, msg->cxm_Data,
460 msg->cxm_Type);
462 if (msg->cxm_Type != CXM_IEVENT)
464 return;
467 kprintf("dump IE: %lx\n"
468 "\tClass %lx"
469 "\tCode %lx"
470 "\tQualifier %lx"
471 "\nEventAddress %lx",
472 msg->cxm_Data, msg->cxm_Data->ie_Class, msg->cxm_Data->ie_Code,
473 msg->cxm_Data->ie_Qualifier, msg->cxm_Data->ie_EventAddress);
477 BOOL CopyInputEvent(struct InputEvent *from, struct InputEvent *to,
478 struct CommoditiesBase *CxBase)
480 memmove(to, from, sizeof(struct InputEvent));
482 if (from->ie_Class == IECLASS_NEWPOINTERPOS)
484 switch (from->ie_SubClass)
486 case IESUBCLASS_PIXEL :
487 if ((to->ie_EventAddress = AllocVec(sizeof(struct IEPointerPixel),
488 MEMF_ANY)) == NULL)
490 return FALSE;
493 memmove(to->ie_EventAddress, from->ie_EventAddress, sizeof(struct IEPointerPixel));
494 break;
496 case IESUBCLASS_TABLET :
497 if ((to->ie_EventAddress = AllocVec(sizeof(struct IEPointerTablet),
498 MEMF_ANY)) == NULL)
500 return FALSE;
503 memmove(to->ie_EventAddress, from->ie_EventAddress, sizeof(struct IEPointerTablet));
504 break;
506 case IESUBCLASS_NEWTABLET :
507 if ((to->ie_EventAddress = AllocVec(sizeof(struct IENewTablet),
508 MEMF_ANY)) == NULL)
510 return FALSE;
513 memmove(to->ie_EventAddress, from->ie_EventAddress, sizeof(struct IENewTablet));
514 break;
516 default :
517 break;
521 return TRUE;
525 AROS_UFH2(struct InputEvent *, cxIHandler,
526 AROS_UFHA(struct InputEvent * , events, A0),
527 AROS_UFHA(struct CommoditiesBase *, CxBase, A1))
529 AROS_USERFUNC_INIT
531 return AROS_UFC2(struct InputEvent *, AROS_ASMSYMNAME(CxTree),
532 AROS_UFCA(struct InputEvent * , events , A0),
533 AROS_UFCA(struct CommoditiesBase *, CxBase , A6));
535 AROS_USERFUNC_EXIT