Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / libs / commodities / commodities_inputhandler.c
blob2ad91a73dee9b9da473c12acabaa49499a7e217f
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 AROS_UFH2(struct InputEvent *, CxTree,
61 AROS_UFHA(struct InputEvent * , events , A0),
62 AROS_UFHA(struct CommoditiesBase *, CxBase , A6))
64 AROS_USERFUNC_INIT
66 CxObj *co;
67 CxMsg *tempMsg, *msg;
68 struct Node *node, *succ;
70 if (events == NULL)
72 return NULL;
75 ObtainSemaphore(&CxBase->cx_SignalSemaphore);
77 if (IsListEmpty(&CxBase->cx_BrokerList))
79 ReleaseSemaphore(&CxBase->cx_SignalSemaphore);
81 return events;
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);
103 #if SUPERDEBUG
105 CxObj *node;
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);
115 else
117 kprintf("Something else\n");
121 #endif
123 /* Route all messages to the first broker */
125 co = (CxObj *)GetHead(&CxBase->cx_BrokerList);
127 #if SUPERDEBUG
128 kprintf("Initial broker: %s\n", co->co_Ext.co_BExt->bext_Name);
129 #endif
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);
153 msg->cxm_Level--;
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)
160 // {
161 // kprintf("Returnobj (broker) = %s\n",
162 // co->co_Ext.co_BExt->bext_Name);
163 // }
166 /* If there are no more objects that shall process the event, we
167 link it in to the list of ready input events */
169 if (co == NULL)
171 ProduceEvent(msg, CxBase);
172 continue;
175 #if DEBUG
176 DEBUG_CXTREE(
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,
186 co);
188 #endif
190 /* Route the message to the next object */
192 ROUTECxMsg(msg, (CxObj *)GetSucc(&co->co_Node));
194 if (!(co->co_Flags & COF_ACTIVE))
196 continue;
199 DEBUG_CXTREE(dprintf("CxTree: Object %p Type %d\n", co, CXOBJType(co)));
201 switch (CXOBJType(co))
203 case CX_INVALID:
204 DEBUG_CXTREE(dprintf("CxTree: CX_INVALID\n"));
205 break;
207 case CX_FILTER:
208 DEBUG_CXTREE(dprintf("CxTree: CX_FILTER\n"));
210 DEBUG_CXTREE(dprintf("CxTree: Filter 0x%lx\n",
211 msg->cxm_Type));
213 if ((co->co_Error & COERR_BADFILTER))
215 DEBUG_CXTREE(dprintf("CxTree: bad filter!\n"));
216 break;
219 if (msg->cxm_Type == CXM_IEVENT)
221 DEBUG_CXTREE(dprintf("CxTree: Data 0x%lx FilterIX 0x%lx\n",
222 msg->cxm_Data,
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);
229 else
231 DEBUG_CXTREE(dprintf("CxTree: filter not matched\n"));
234 else
236 DEBUG_CXTREE(dprintf("CxTree: no CXM_EVENT\n"));
238 break;
240 case CX_TYPEFILTER:
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);
247 break;
249 case CX_SEND:
250 DEBUG_CXTREE(dprintf("CxTree: CX_SEND\n"));
251 SendFunc(msg, co, CxBase);
252 break;
254 case CX_SIGNAL:
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);
260 break;
262 case CX_TRANSLATE:
263 DEBUG_CXTREE(dprintf("CxTree: CX_TRANSLATE\n"));
264 TransFunc(msg, co, CxBase);
265 break;
267 case CX_BROKER:
268 DEBUG_CXTREE(dprintf("CxTree: CX_BROKER\n"));
269 DivertCxMsg(msg, co, co);
270 break;
272 case CX_DEBUG:
273 DEBUG_CXTREE(dprintf("CxTree: CX_DEBUG\n"));
274 DebugFunc(msg, co, CxBase);
275 break;
277 case CX_CUSTOM:
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.
291 #ifdef __MORPHOS__
292 REG_A7 -= 8;
293 *(CxMsg**)REG_A7 = msg;
294 *(CxObj**)(REG_A7 + 4) = co;
295 #endif
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));
300 #ifdef __MORPHOS__
301 REG_A7 += 8;
302 #endif
304 break;
306 case CX_ZERO:
307 DEBUG_CXTREE(dprintf("CxTree: CX_ZERO\n"));
308 ProduceEvent(msg, CxBase);
309 break;
312 DEBUG_CXTREE(dprintf("CxTree: done\n"));
315 ReleaseSemaphore(&CxBase->cx_SignalSemaphore);
317 return CxBase->cx_IEvents;
319 AROS_USERFUNC_EXIT
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);
345 DisposeCxMsg(msg);
349 static void SendFunc(CxMsg *msg, CxObj *co, struct CommoditiesBase *CxBase)
351 CxMsg *tempMsg;
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)
360 return;
363 tempMsg = (CxMsg *)AllocCxStructure(CX_MESSAGE, CXM_DOUBLE,
364 (struct Library *)CxBase);
366 if (tempMsg == NULL)
368 DEBUG_SENDFUNC(dprintf("SendFunc: failed!\n"));
369 return;
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;
390 CxMsg *msg2;
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"));
411 break;
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);
429 DisposeCxMsg(msg);
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,
438 msg->cxm_Type);
440 if (msg->cxm_Type != CXM_IEVENT)
442 return;
445 kprintf("dump IE: %lx\n"
446 "\tClass %lx"
447 "\tCode %lx"
448 "\tQualifier %lx"
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),
466 MEMF_ANY)) == NULL)
468 return FALSE;
471 bcopy(from->ie_EventAddress, to->ie_EventAddress, sizeof(struct IEPointerPixel));
472 break;
474 case IESUBCLASS_TABLET :
475 if ((to->ie_EventAddress = AllocVec(sizeof(struct IEPointerTablet),
476 MEMF_ANY)) == NULL)
478 return FALSE;
481 bcopy(from->ie_EventAddress, to->ie_EventAddress, sizeof(struct IEPointerTablet));
482 break;
484 case IESUBCLASS_NEWTABLET :
485 if ((to->ie_EventAddress = AllocVec(sizeof(struct IENewTablet),
486 MEMF_ANY)) == NULL)
488 return FALSE;
491 bcopy(from->ie_EventAddress, to->ie_EventAddress, sizeof(struct IENewTablet));
492 break;
494 default :
495 break;
499 return TRUE;
503 AROS_UFH2(struct InputEvent *, cxIHandler,
504 AROS_UFHA(struct InputEvent * , events, A0),
505 AROS_UFHA(struct CommoditiesBase *, CxBase, A1))
507 AROS_USERFUNC_INIT
509 return AROS_UFC2(struct InputEvent *, AROS_ASMSYMNAME(CxTree),
510 AROS_UFCA(struct InputEvent * , events , A0),
511 AROS_UFCA(struct CommoditiesBase *, CxBase , A6));
513 AROS_USERFUNC_EXIT