2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: Commodities input handler
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
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
30 ??.08.97 SDuvan Implemented
31 16.08.99 Working version
34 /***************************************************************************/
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>
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;
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 AROS_UFH2(struct InputEvent
*, CxTree
,
61 AROS_UFHA(struct InputEvent
* , events
, A0
),
62 AROS_UFHA(struct CommoditiesBase
*, CxBase
, A6
))
68 struct Node
*node
, *succ
;
75 ObtainSemaphore(&CxBase
->cx_SignalSemaphore
);
77 if (IsListEmpty(&CxBase
->cx_BrokerList
))
79 ReleaseSemaphore(&CxBase
->cx_SignalSemaphore
);
84 /* Take care of the processed input events */
85 ForeachNodeSafe(&CxBase
->cx_GeneratedInputEvents
, node
, succ
)
87 struct GeneratedInputEvent
*tempEvent
;
89 tempEvent
= (struct GeneratedInputEvent
*)(((UBYTE
*)node
) - offsetof(struct GeneratedInputEvent
, node
));
90 FreeCxStructure(tempEvent
, CX_INPUTEVENT
, (struct Library
*)CxBase
);
93 CxBase
->cx_IEvents
= NULL
;
94 CxBase
->cx_EventExtra
= &CxBase
->cx_IEvents
;
95 NEWLIST(&CxBase
->cx_GeneratedInputEvents
);
97 /* Free all the replied messages */
98 while ((tempMsg
= (CxMsg
*)GetMsg(&CxBase
->cx_MsgPort
)) != NULL
)
100 FreeCxStructure(tempMsg
, CX_MESSAGE
, (struct Library
*)CxBase
);
107 kprintf("List of brokers:\n");
109 ForeachNode(&CxBase
->cx_BrokerList
, node
)
111 if (CXOBJType(node
) == CX_BROKER
)
113 kprintf("B: %s\n", node
->co_Ext
.co_BExt
->bext_Name
);
117 kprintf("Something else\n");
123 /* Route all messages to the first broker */
125 co
= (CxObj
*)GetHead(&CxBase
->cx_BrokerList
);
128 kprintf("Initial broker: %s\n", co
->co_Ext
.co_BExt
->bext_Name
);
131 ForeachNode(&CxBase
->cx_MessageList
, tempMsg
)
133 ROUTECxMsg(tempMsg
, co
);
136 AddIEvents(events
); /* Add the new events (incapsulated in commodtity
137 messages) to the message list. */
139 /***************************************************************************/
141 /* Process the new events */
143 while ((msg
= (CxMsg
*)GetHead(&CxBase
->cx_MessageList
)) != NULL
)
145 co
= msg
->cxm_Routing
;
147 DEBUG_CXTREE(dprintf("CxTree: Msg %p Object %p\n", msg
, co
));
149 while (co
== NULL
&& msg
->cxm_Level
!= 0)
151 // kprintf("Next level %i\n", msg->cxm_Level - 1);
154 co
= msg
->cxm_retObj
[msg
->cxm_Level
];
155 co
= (CxObj
*)GetSucc(&co
->co_Node
);
157 // kprintf("Found return object %p\n", co);
159 // if (CXOBJType(co) == CX_BROKER)
161 // kprintf("Returnobj (broker) = %s\n",
162 // co->co_Ext.co_BExt->bext_Name);
166 /* If there are no more objects that shall process the event, we
167 link it in to the list of ready input events */
171 ProduceEvent(msg
, CxBase
);
178 if(CXOBJType(co
) == CX_BROKER
)
179 kprintf("Broker: %s\n", co
->co_Ext
.co_BExt
->bext_Name
);
181 if(co
->co_Node
.ln_Succ
!= NULL
&&
182 co
->co_Node
.ln_Succ
->ln_Type
== CX_BROKER
)
183 kprintf("Routing to next broker %s (this broker=%s) %p\n",
184 ((CxObj
*)(co
->co_Node
.ln_Succ
))->co_Ext
.co_BExt
->bext_Name
,
185 co
->co_Ext
.co_BExt
->bext_Name
,
190 /* Route the message to the next object */
192 ROUTECxMsg(msg
, (CxObj
*)GetSucc(&co
->co_Node
));
194 if (!(co
->co_Flags
& COF_ACTIVE
))
199 DEBUG_CXTREE(dprintf("CxTree: Object %p Type %d\n", co
, CXOBJType(co
)));
201 switch (CXOBJType(co
))
204 DEBUG_CXTREE(dprintf("CxTree: CX_INVALID\n"));
208 DEBUG_CXTREE(dprintf("CxTree: CX_FILTER\n"));
210 DEBUG_CXTREE(dprintf("CxTree: Filter 0x%lx\n",
213 if ((co
->co_Error
& COERR_BADFILTER
))
215 DEBUG_CXTREE(dprintf("CxTree: bad filter!\n"));
219 if (msg
->cxm_Type
== CXM_IEVENT
)
221 DEBUG_CXTREE(dprintf("CxTree: Data 0x%lx FilterIX 0x%lx\n",
223 co
->co_Ext
.co_FilterIX
));
224 if (MatchIX(msg
->cxm_Data
, co
->co_Ext
.co_FilterIX
) != 0)
226 DEBUG_CXTREE(dprintf("CxTree: filter matched\n"));
227 DivertCxMsg(msg
, co
, co
);
231 DEBUG_CXTREE(dprintf("CxTree: filter not matched\n"));
236 DEBUG_CXTREE(dprintf("CxTree: no CXM_EVENT\n"));
241 DEBUG_CXTREE(dprintf("CxTree: CX_TYPEFILTER\n"));
242 if ((msg
->cxm_Type
& co
->co_Ext
.co_TypeFilter
) != 0)
244 DEBUG_CXTREE(dprintf("CxTree: hit\n"));
245 DivertCxMsg(msg
, co
, co
);
250 DEBUG_CXTREE(dprintf("CxTree: CX_SEND\n"));
251 SendFunc(msg
, co
, CxBase
);
255 DEBUG_CXTREE(dprintf("CxTree: CX_SIGNAL Task 0x%lx <%s>\n",
256 co
->co_Ext
.co_SignalExt
->sixt_Task
,
257 co
->co_Ext
.co_SignalExt
->sixt_Task
->tc_Node
.ln_Name
));
258 Signal(co
->co_Ext
.co_SignalExt
->sixt_Task
,
259 1 << co
->co_Ext
.co_SignalExt
->sixt_SigBit
);
263 DEBUG_CXTREE(dprintf("CxTree: CX_TRANSLATE\n"));
264 TransFunc(msg
, co
, CxBase
);
268 DEBUG_CXTREE(dprintf("CxTree: CX_BROKER\n"));
269 DivertCxMsg(msg
, co
, co
);
273 DEBUG_CXTREE(dprintf("CxTree: CX_DEBUG\n"));
274 DebugFunc(msg
, co
, CxBase
);
278 DEBUG_CXTREE(dprintf("CxTree: CX_CUSTOM\n"));
279 msg
->cxm_ID
= co
->co_Ext
.co_CustomExt
->cext_ID
;
281 DEBUG_CXTREE(dprintf("CxTree: Action 0x%lx\n",
282 co
->co_Ext
.co_CustomExt
->cext_Action
));
283 /* Action shouldn't be NULL, but well, sometimes it is...
285 if (co
->co_Ext
.co_CustomExt
->cext_Action
)
287 /* The autodocs suggest the arguments should be passed on the stack.
288 * But they were also in a0/a1 and some things seem to rely on that.
289 * Let's also pass CxBase in a6 just in case.
293 *(CxMsg
**)REG_A7
= msg
;
294 *(CxObj
**)(REG_A7
+ 4) = co
;
296 AROS_UFC3(void, co
->co_Ext
.co_CustomExt
->cext_Action
,
297 AROS_UFCA(CxMsg
*, msg
, A0
),
298 AROS_UFCA(CxObj
*, co
, A1
),
299 AROS_UFCA(struct CommoditiesBase
*, CxBase
, A6
));
307 DEBUG_CXTREE(dprintf("CxTree: CX_ZERO\n"));
308 ProduceEvent(msg
, CxBase
);
312 DEBUG_CXTREE(dprintf("CxTree: done\n"));
315 ReleaseSemaphore(&CxBase
->cx_SignalSemaphore
);
317 return CxBase
->cx_IEvents
;
323 static void ProduceEvent(CxMsg
*msg
, struct CommoditiesBase
*CxBase
)
325 struct GeneratedInputEvent
*temp
;
327 if ((temp
= (struct GeneratedInputEvent
*)AllocCxStructure(CX_INPUTEVENT
, 0,
328 (struct Library
*)CxBase
)) != NULL
)
330 if (!CopyInputEvent(msg
->cxm_Data
, &temp
->ie
, CxBase
))
332 DEBUG_COPYIEVENT(dprintf("ProduceEvent: CopyInputEvent() failed!\n"));
335 /* Put the input event last in the ready list and update bookkeeping */
336 temp
->ie
.ie_NextEvent
= NULL
;
338 *(CxBase
->cx_EventExtra
) = &temp
->ie
;
339 CxBase
->cx_EventExtra
= &temp
->ie
.ie_NextEvent
;
341 AddTail((struct List
*)&CxBase
->cx_GeneratedInputEvents
,
342 (struct Node
*)&temp
->node
);
349 static void SendFunc(CxMsg
*msg
, CxObj
*co
, struct CommoditiesBase
*CxBase
)
352 struct InputEvent
*saveIE
; /* To save the InputEvent pointer
353 from being destroyed by CopyMem() */
355 DEBUG_SENDFUNC(dprintf("SendFunc: msg %p co %p MsgPort %p ID 0x%lx\n",
356 msg
, co
, co
->co_Ext
.co_SendExt
->sext_MsgPort
, co
->co_Ext
.co_SendExt
->sext_ID
));
358 if (co
->co_Ext
.co_SendExt
->sext_MsgPort
== NULL
)
363 tempMsg
= (CxMsg
*)AllocCxStructure(CX_MESSAGE
, CXM_DOUBLE
,
364 (struct Library
*)CxBase
);
368 DEBUG_SENDFUNC(dprintf("SendFunc: failed!\n"));
372 saveIE
= tempMsg
->cxm_Data
;
373 CopyMem(msg
, tempMsg
, sizeof(CxMsg
));
374 tempMsg
->cxm_Data
= saveIE
;
376 if (!CopyInputEvent(msg
->cxm_Data
, tempMsg
->cxm_Data
, CxBase
))
378 DEBUG_COPYIEVENT(dprintf("SendFunc: CopyInputEvent() failed!\n"));
381 tempMsg
->cxm_ID
= co
->co_Ext
.co_SendExt
->sext_ID
;
383 PutMsg(co
->co_Ext
.co_SendExt
->sext_MsgPort
, (struct Message
*)tempMsg
);
387 static void TransFunc(CxMsg
*msg
, CxObj
*co
, struct CommoditiesBase
*CxBase
)
389 struct InputEvent
*event
;
392 DEBUG_TRANSFUNC(dprintf("TransFunc: msg %p co %p ie %p\n",
393 msg
, co
, co
->co_Ext
.co_IE
));
395 if (co
->co_Ext
.co_IE
!= NULL
)
397 event
= co
->co_Ext
.co_IE
;
401 struct InputEvent
*saveIE
; /* To save the InputEvent pointer
402 from being destroyed by CopyMem() */
404 DEBUG_TRANSFUNC(dprintf("TransFunc: Generate class %d code 0x%x\n",
405 event
->ie_Class
, event
->ie_Code
));
407 if ((msg2
= (CxMsg
*)AllocCxStructure(CX_MESSAGE
, CXM_DOUBLE
,
408 (struct Library
*)CxBase
)) == NULL
)
410 DEBUG_TRANSFUNC(dprintf("TransFunc: failed!\n"));
414 saveIE
= msg2
->cxm_Data
;
415 CopyMem(msg
, msg2
, sizeof(CxMsg
));
416 msg2
->cxm_Data
= saveIE
;
418 /* Don't care about errors for now */
419 if (!CopyInputEvent(event
, msg2
->cxm_Data
, CxBase
))
421 DEBUG_COPYIEVENT(dprintf("TransFunc: CopyInputEvent() failed!\n"));
424 AddHead(&CxBase
->cx_MessageList
, (struct Node
*)msg2
);
426 } while ((event
= event
->ie_NextEvent
) != NULL
);
433 static void DebugFunc(CxMsg
*msg
, CxObj
*co
, struct CommoditiesBase
*CxBase
)
435 kprintf("\n----\nDEBUG NODE: %lx, ID: %lx\n"
436 "\tCxMsg: %lx, type: %x, data %lx destination %lx\n",
437 co
, co
->co_Ext
.co_DebugID
, msg
->cxm_Routing
, msg
->cxm_Data
,
440 if (msg
->cxm_Type
!= CXM_IEVENT
)
445 kprintf("dump IE: %lx\n"
449 "\nEventAddress %lx",
450 msg
->cxm_Data
, msg
->cxm_Data
->ie_Class
, msg
->cxm_Data
->ie_Code
,
451 msg
->cxm_Data
->ie_Qualifier
, msg
->cxm_Data
->ie_EventAddress
);
455 BOOL
CopyInputEvent(struct InputEvent
*from
, struct InputEvent
*to
,
456 struct CommoditiesBase
*CxBase
)
458 bcopy(from
, to
, sizeof(struct InputEvent
));
460 if (from
->ie_Class
== IECLASS_NEWPOINTERPOS
)
462 switch (from
->ie_SubClass
)
464 case IESUBCLASS_PIXEL
:
465 if ((to
->ie_EventAddress
= AllocVec(sizeof(struct IEPointerPixel
),
471 bcopy(from
->ie_EventAddress
, to
->ie_EventAddress
, sizeof(struct IEPointerPixel
));
474 case IESUBCLASS_TABLET
:
475 if ((to
->ie_EventAddress
= AllocVec(sizeof(struct IEPointerTablet
),
481 bcopy(from
->ie_EventAddress
, to
->ie_EventAddress
, sizeof(struct IEPointerTablet
));
484 case IESUBCLASS_NEWTABLET
:
485 if ((to
->ie_EventAddress
= AllocVec(sizeof(struct IENewTablet
),
491 bcopy(from
->ie_EventAddress
, to
->ie_EventAddress
, sizeof(struct IENewTablet
));
503 AROS_UFH2(struct InputEvent
*, cxIHandler
,
504 AROS_UFHA(struct InputEvent
* , events
, A0
),
505 AROS_UFHA(struct CommoditiesBase
*, CxBase
, A1
))
509 return AROS_UFC2(struct InputEvent
*, AROS_ASMSYMNAME(CxTree
),
510 AROS_UFCA(struct InputEvent
* , events
, A0
),
511 AROS_UFCA(struct CommoditiesBase
*, CxBase
, A6
));