2 Copyright © 2002-2006, The AROS Development Team. All rights reserved.
9 #include <exec/types.h>
10 #include <clib/alib_protos.h>
11 #include <libraries/commodities.h>
12 #include <proto/commodities.h>
13 #include <proto/exec.h>
14 #include <proto/intuition.h>
15 #include <proto/utility.h>
16 #include <proto/muimaster.h>
18 #include "muimaster_intern.h"
27 extern struct Library
*MUIMasterBase
;
29 AROS_UFH2S(void, cpy_func
,
30 AROS_UFHA(UBYTE
, chr
, D0
),
31 AROS_UFHA(STRPTR
*, strPtrPtr
, A3
))
35 *(*strPtrPtr
)++ = chr
;
40 AROS_UFH2S(void, len_func
,
41 AROS_UFHA(UBYTE
, chr
, D0
),
42 AROS_UFHA(LONG
*, lenPtr
, A3
))
53 * Notify class is superclass of all other MUI classes.
57 MUIA_ApplicationObject [..G] done
58 MUIA_AppMessage [..G] dummy, no struct AppMessage
59 MUIA_HelpLine [ISG] done
60 MUIA_HelpNode [ISG] done
61 MUIA_NoNotify [.S.] done
62 MUIA_ObjectID [ISG] done
63 MUIA_Parent [..G] done
64 MUIA_Revision [..G] done
65 MUIA_UserData [ISG] done
66 MUIA_Version [..G] done
69 MUIM_Export dummy & redefine in subclasses w/ childs
70 MUIM_FindUData redefine in subclasses w/ childs
72 MUIM_GetUData redefine in subclasses w/ childs
73 MUIM_Import dummy & redefine in subclasses w/ childs
75 MUIM_KillNotifyObj done (semantic ?)
81 MUIM_SetUData redefine in subclasses w/ childs
82 MUIM_SetUDataOnce redefine in subclasses w/ childs
87 static const int __version
= 1;
88 static const int __revision
= 1;
91 * Notification handler
93 typedef struct NotifyNode
95 struct MinNode nn_Node
;
96 BOOL nn_Active
; /* When TRUE, it means that the notification is currently being handled */
97 /* It's used to prevent loops */
102 IPTR
*nn_Params
; /* FIXME: use nn_Params[1] and tweak stuff below */
103 IPTR
*nn_NewParams
; /* For MUIV_EveryTime */
106 typedef struct NotifyNodeIX
108 struct NotifyNode nn
;
112 static struct NotifyNode
*CreateNNode (struct MUI_NotifyData
*data
, struct MUIP_Notify
*msg
)
116 struct NotifyNode
*nnode
;
118 if ((msg
->TrigAttr
== MUIA_Window_InputEvent
) && (msg
->TrigVal
!= MUIV_EveryTime
))
120 IX ix
= {IX_VERSION
};
122 if (ParseIX((CONST_STRPTR
)msg
->TrigVal
, &ix
) != 0) return NULL
;
124 if ((nnode
= (struct NotifyNode
*)mui_alloc_struct(struct NotifyNodeIX
)))
126 ((struct NotifyNodeIX
*)nnode
)->ix
= ix
;
131 nnode
= mui_alloc_struct(struct NotifyNode
);
134 if (!nnode
) return NULL
;
136 nnode
->nn_Active
= FALSE
;
137 nnode
->nn_TrigAttr
= msg
->TrigAttr
;
138 nnode
->nn_TrigVal
= msg
->TrigVal
;
139 nnode
->nn_DestObj
= msg
->DestObj
;
140 nnode
->nn_NumParams
= msg
->FollowParams
;
142 /* Allocate one more IPTR (FollowParams + 1) as some ext apps/classes
143 forget trailing NULLs in methods like MUIM_MultiSet and MUI seems
144 like it can live with that (without crashing) */
146 paramsize
= (msg
->FollowParams
+ 1);
147 if (msg
->TrigVal
== MUIV_EveryTime
)
152 if ((nnode
->nn_Params
= (IPTR
*)mui_alloc(paramsize
* sizeof(IPTR
))))
154 IPTR
*par
= (IPTR
*)&msg
->FollowParams
;
156 for (i
= 0; i
< msg
->FollowParams
; i
++)
158 nnode
->nn_Params
[i
] = *(par
+ i
+ 1);
161 if (msg
->TrigVal
== MUIV_EveryTime
)
163 nnode
->nn_NewParams
= nnode
->nn_Params
+ msg
->FollowParams
+ 1;
164 for (i
= 0; i
< msg
->FollowParams
; i
++)
166 nnode
->nn_NewParams
[i
] = *(par
+ i
+ 1);
178 static void DeleteNNode (struct MUI_NotifyData
*data
, struct NotifyNode
*nnode
)
180 mui_free(nnode
->nn_Params
);
185 IPTR
Notify__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
);
190 IPTR
Notify__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
192 struct MUI_NotifyData
*data
;
193 struct TagItem
*tags
= msg
->ops_AttrList
;
196 obj
= (Object
*)DoSuperMethodA(cl
, obj
, (Msg
)msg
);
197 if (!obj
) return FALSE
;
199 data
= INST_DATA(cl
, obj
);
201 while ((tag
= NextTagItem((const struct TagItem
**)&tags
)) != NULL
)
206 data
->mnd_HelpLine
= (LONG
)tag
->ti_Data
;
210 data
->mnd_HelpNode
= (STRPTR
)tag
->ti_Data
;
214 data
->mnd_ObjectID
= (ULONG
)tag
->ti_Data
;
218 data
->mnd_UserData
= (IPTR
)tag
->ti_Data
;
230 IPTR
Notify__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
232 struct MinNode
*node
, *tmp
;
233 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
235 if (data
->mnd_NotifyList
)
237 for (node
= data
->mnd_NotifyList
->mlh_Head
; node
->mln_Succ
; node
= tmp
)
239 tmp
= node
->mln_Succ
;
240 DeleteNNode(data
, (struct NotifyNode
*)node
);
242 mui_free(data
->mnd_NotifyList
);
245 return DoSuperMethodA(cl
, obj
, msg
);
248 static void check_notify (NNode nnode
, Object
*obj
, struct TagItem
*tag
)
253 BOOL donotify
= FALSE
;
255 /* is it the good attribute ? */
256 if (tag
->ti_Tag
!= nnode
->nn_TrigAttr
)
259 /* Is the notification already being performed? */
260 if (nnode
->nn_Active
)
265 D(bug("Notifyloop detected! (#%d)\n", counter
++));
266 D(bug(" Source object: 0x%x", obj
));
268 switch((IPTR
)nnode
->nn_DestObj
)
270 case MUIV_Notify_Application
:
271 D(bug(" Dest object: 0x%x (MUIV_Notify_Application)\n", _app(obj
)));
273 case MUIV_Notify_Self
:
274 D(bug(" Dest object: 0x%x (MUIV_Notify_Self)\n", obj
));
277 case MUIV_Notify_Window
:
278 if (muiRenderInfo(obj
)) /* otherwise _win(obj) does NULL access! */
280 D(bug(" Dest object: 0x%x (MUIV_Notify_Window)\n", _win(obj
)));
284 D(bug(" Dest object: INVALID (MUIV_Notify_Window, but no muiRenderInfo)\n"));
288 D(bug(" Dest object: 0x%x\n", nnode
->nn_DestObj
));
291 D(bug(" Attribute: 0x%x Value: 0x%x\n", tag
->ti_Tag
, tag
->ti_Data
));
297 if (nnode
->nn_TrigVal
== MUIV_EveryTime
)
301 else if (nnode
->nn_TrigAttr
== MUIA_Window_InputEvent
)
303 if (MatchIX((struct InputEvent
*)tag
->ti_Data
, &((struct NotifyNodeIX
*)nnode
)->ix
))
308 else if (nnode
->nn_TrigVal
== tag
->ti_Data
)
315 switch((IPTR
)nnode
->nn_DestObj
)
317 case MUIV_Notify_Application
:
320 case MUIV_Notify_Self
:
323 case MUIV_Notify_Window
:
324 if (muiRenderInfo(obj
)) /* otherwise _win(obj) does NULL access! */
334 destobj
= nnode
->nn_DestObj
;
337 params
= nnode
->nn_Params
;
338 if (nnode
->nn_TrigVal
== MUIV_EveryTime
)
340 params
= nnode
->nn_NewParams
;
342 for (i
= 1; i
< nnode
->nn_NumParams
; i
++)
344 switch(nnode
->nn_Params
[i
])
346 case MUIV_TriggerValue
:
347 params
[i
] = tag
->ti_Data
;
350 case MUIV_NotTriggerValue
:
351 params
[i
] = !tag
->ti_Data
;
357 nnode
->nn_Active
= TRUE
;
360 DoMethodA(destobj
, (Msg
)params
);
362 nnode
->nn_Active
= FALSE
;
369 IPTR
Notify__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
371 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
372 struct TagItem
*tags
= msg
->ops_AttrList
;
373 BOOL no_notify
= FALSE
;
375 struct MinNode
*node
;
377 /* There are many ways to find out what tag items provided by set()
378 ** we do know. The best way should be using NextTagItem() and simply
379 ** browsing through the list.
381 while ((tag
= NextTagItem((const struct TagItem
**)&tags
)) != NULL
)
386 data
->mnd_HelpLine
= (LONG
)tag
->ti_Data
;
390 data
->mnd_HelpNode
= (STRPTR
)tag
->ti_Data
;
394 if (tag
->ti_Data
== TRUE
)
399 data
->mnd_ObjectID
= (ULONG
)tag
->ti_Data
;
403 data
->mnd_UserData
= tag
->ti_Data
;
409 * check for notifications
411 if (!data
->mnd_NotifyList
|| no_notify
)
414 tags
= msg
->ops_AttrList
;
415 while ((tag
= NextTagItem((const struct TagItem
**)&tags
)))
419 node
= data
->mnd_NotifyList
->mlh_Head
;
421 node
= node
->mln_Succ
424 check_notify((NNode
)node
, obj
, tag
);
435 IPTR
Notify__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
437 /* small macro to simplify return value storage */
438 #define STORE *(msg->opg_Storage)
440 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
442 //kprintf("*** Notify->GET\n");
443 switch (msg
->opg_AttrID
)
445 case MUIA_ApplicationObject
:
446 if (data
->mnd_GlobalInfo
) STORE
= (IPTR
)data
->mnd_GlobalInfo
->mgi_ApplicationObject
;
450 case MUIA_AppMessage
: /* struct AppMessage ? */
455 STORE
= (IPTR
)data
->mnd_HelpLine
;
459 STORE
= (IPTR
)data
->mnd_HelpNode
;
463 STORE
= (IPTR
)data
->mnd_ObjectID
;
467 STORE
= (IPTR
)data
->mnd_ParentObject
;
475 STORE
= data
->mnd_UserData
;
483 return DoSuperMethodA(cl
,obj
,(Msg
)msg
);
488 * MUIM_CallHook : Call a standard amiga callback hook, defined by a Hook
491 IPTR
Notify__MUIM_CallHook(struct IClass
*cl
, Object
*obj
, struct MUIP_CallHook
*msg
)
493 if (msg
->Hook
->h_Entry
)
494 return CallHookPkt(msg
->Hook
,obj
, &msg
->param1
);
500 * MUIM_Export : to export an objects "contents" to a dataspace object.
502 /* nothing to export */
505 * MUIM_FindUData : tests if the MUIA_UserData of the object
506 * contains the given <udata> and returns the object pointer in this case.
508 IPTR
Notify__MUIM_FindUData(struct IClass
*cl
, Object
*obj
, struct MUIP_FindUData
*msg
)
510 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
512 if (data
->mnd_UserData
== msg
->udata
)
521 * MUIM_GetUData : This method tests if the MUIA_UserData of the object
522 * contains the given <udata> and gets <attr> to <storage> for itself
525 IPTR
Notify__MUIM_GetUData(struct IClass
*cl
, Object
*obj
, struct MUIP_GetUData
*msg
)
527 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
529 if (data
->mnd_UserData
== msg
->udata
)
531 get(obj
, msg
->attr
, msg
->storage
);
539 * MUIM_Import : to import an objects "contents" from a dataspace object.
541 /* nothing to import */
544 * MUIM_KillNotify : kills previously given notifications on specific attributes.
546 IPTR
Notify__MUIM_KillNotify(struct IClass
*cl
, Object
*obj
, struct MUIP_KillNotify
*msg
)
548 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
549 struct MinNode
*node
;
550 struct NotifyNode
*nnode
;
552 if (!data
->mnd_NotifyList
) return 0;
554 for (node
= data
->mnd_NotifyList
->mlh_Head
; node
->mln_Succ
; node
= node
->mln_Succ
)
557 if (msg
->TrigAttr
== nnode
->nn_TrigAttr
)
559 Remove((struct Node
*)node
);
560 DeleteNNode(data
, nnode
);
569 * MUIM_KillNotifyObj : originally undocumented !
570 * Supposed to kill a notification with a given attr and a given dest.
572 IPTR
Notify__MUIM_KillNotifyObj(struct IClass
*cl
, Object
*obj
, struct MUIP_KillNotifyObj
*msg
)
574 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
575 struct MinNode
*node
;
576 struct NotifyNode
*nnode
;
578 if (!data
->mnd_NotifyList
) return 0;
580 for (node
= data
->mnd_NotifyList
->mlh_Head
; node
->mln_Succ
; node
= node
->mln_Succ
)
583 if ((msg
->TrigAttr
== nnode
->nn_TrigAttr
)
584 && (msg
->dest
== nnode
->nn_DestObj
))
586 Remove((struct Node
*)node
);
587 DeleteNNode(data
, nnode
);
596 * MUIM_MultiSet : Set an attribute for multiple objects.
598 IPTR
Notify__MUIM_MultiSet(struct IClass
*cl
, Object
*obj
, struct MUIP_MultiSet
*msg
)
601 for (destobj_p
= (IPTR
*)&msg
->obj
; (*destobj_p
) != 0; destobj_p
++)
603 set((APTR
)*destobj_p
, msg
->attr
, msg
->val
);
610 * MUIM_NoNotifySet : Acts like MUIM_Set but doesn't trigger any notification.
612 IPTR
Notify__MUIM_NoNotifySet(struct IClass
*cl
, Object
*obj
, struct MUIP_NoNotifySet
*msg
)
614 return SetAttrs(obj
, MUIA_NoNotify
, TRUE
, msg
->attr
, msg
->val
, TAG_DONE
);
619 * MUIM_Notify : Add a notification event handler to an object.
621 IPTR
Notify__MUIM_Notify(struct IClass
*cl
, Object
*obj
, struct MUIP_Notify
*msg
)
623 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
624 struct NotifyNode
*nnode
;
626 if (msg
->FollowParams
< 1)
629 if (data
->mnd_NotifyList
== NULL
)
631 if (!(data
->mnd_NotifyList
= mui_alloc_struct(struct MinList
)))
633 NewList((struct List
*)data
->mnd_NotifyList
);
636 nnode
= CreateNNode(data
, msg
);
640 AddTail((struct List
*)data
->mnd_NotifyList
, (struct Node
*)nnode
);
646 * MUIM_Set : Set an attribute to a value, useful within a MUIM_Notify method.
648 IPTR
Notify__MUIM_Set(struct IClass
*cl
, Object
*obj
, struct MUIP_Set
*msg
)
650 return set(obj
, msg
->attr
, msg
->val
);
654 * MUIM_SetAsString : Set a (text kind) attribute to a string.
656 IPTR
Notify__MUIM_SetAsString(struct IClass
*cl
, Object
*obj
, struct MUIP_SetAsString
*msg
)
662 RawDoFmt(msg
->format
, (ULONG
*)&msg
->val
,
663 (VOID_FUNC
)AROS_ASMSYMNAME(len_func
), &txt_len
);
665 /* D(bug("Notify_SetAsString: fmt=%s, txtlen=%d\n", msg->format, txt_len)); */
666 txt
= AllocVec(txt_len
+ 1, 0);
672 RawDoFmt(msg
->format
, (ULONG
*)&msg
->val
,
673 (VOID_FUNC
)AROS_ASMSYMNAME(cpy_func
), &txtptr
);
676 set(obj
, msg
->attr
, (IPTR
)txt
);
684 * MUIM_SetUData : This method tests if the MUIA_UserData of the object
685 * contains the given <udata> and sets <attr> to <val> for itself in this case.
687 IPTR
Notify__MUIM_SetUData(struct IClass
*cl
, Object
*obj
, struct MUIP_SetUData
*msg
)
689 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
691 if (data
->mnd_UserData
== msg
->udata
)
693 set(obj
, msg
->attr
, msg
->val
);
701 * MUIM_WriteLong : This method simply writes a longword somewhere to memory.
703 IPTR
Notify__MUIM_WriteLong(struct IClass
*cl
, Object
*obj
, struct MUIP_WriteLong
*msg
)
705 *(msg
->memory
) = msg
->val
;
711 * MUIM_WriteString : This method simply copies a string somewhere to memory.
713 IPTR
Notify__MUIM_WriteString(struct IClass
*cl
, Object
*obj
, struct MUIP_WriteString
*msg
)
715 strcpy(msg
->memory
, msg
->str
);
719 /**************************************************************************
721 **************************************************************************/
722 IPTR
Notify__MUIM_ConnectParent(struct IClass
*cl
, Object
*obj
, struct MUIP_ConnectParent
*msg
)
724 //struct MUI_NotifyData *data = INST_DATA(cl, obj);
726 /* Objects only have parents if they are inside a group or family object, no idea
727 ** why MUIA_Parent belongs to the notify class then
729 /* data->mnd_ParentObject = msg->parent;*/
730 muiGlobalInfo(obj
) = muiGlobalInfo(msg
->parent
);
734 /**************************************************************************
735 MUIM_DisconnectParent
736 **************************************************************************/
737 IPTR
Notify__MUIM_DisconnectParent(struct IClass
*cl
, Object
*obj
, struct MUIP_DisconnectParent
*msg
)
739 //struct MUI_NotifyData *data = INST_DATA(cl, obj);
740 /* data->mnd_ParentObject = NULL;*/
741 #if 0 /* Some apps (YAM) seem to access this even after disconnection (Bernd Roesch) */
742 muiGlobalInfo(obj
) = NULL
;
747 /**************************************************************************
749 **************************************************************************/
750 IPTR
Notify__MUIM_GetConfigItem(struct IClass
*cl
, Object
*obj
, struct MUIP_GetConfigItem
*msg
)
752 IPTR found
= DoMethod(muiGlobalInfo(obj
)->mgi_Configdata
,MUIM_Dataspace_Find
,msg
->id
);
756 *msg
->storage
= (IPTR
*)found
;
766 BOOPSI_DISPATCHER(IPTR
, Notify_Dispatcher
, cl
, obj
, msg
)
768 switch (msg
->MethodID
)
770 case OM_NEW
: return Notify__OM_NEW(cl
, obj
, (struct opSet
*) msg
);
771 case OM_DISPOSE
: return Notify__OM_DISPOSE(cl
, obj
, msg
);
772 case OM_SET
: return Notify__OM_SET(cl
, obj
, (struct opSet
*)msg
);
773 case OM_GET
: return Notify__OM_GET(cl
, obj
, (struct opGet
*)msg
);
775 case MUIM_CallHook
: return Notify__MUIM_CallHook(cl
, obj
, (APTR
)msg
);
776 case MUIM_Export
: return TRUE
;
777 case MUIM_FindUData
: return Notify__MUIM_FindUData(cl
, obj
, (APTR
)msg
);
778 case MUIM_GetUData
: return Notify__MUIM_GetUData(cl
, obj
, (APTR
)msg
);
779 case MUIM_Import
: return TRUE
;
780 case MUIM_KillNotify
: return Notify__MUIM_KillNotify(cl
, obj
, (APTR
)msg
);
781 case MUIM_KillNotifyObj
: return Notify__MUIM_KillNotifyObj(cl
, obj
, (APTR
)msg
);
782 case MUIM_MultiSet
: return Notify__MUIM_MultiSet(cl
, obj
, (APTR
)msg
);
783 case MUIM_NoNotifySet
: return Notify__MUIM_NoNotifySet(cl
, obj
, (APTR
)msg
);
784 case MUIM_Notify
: return Notify__MUIM_Notify(cl
, obj
, (APTR
)msg
);
785 case MUIM_Set
: return Notify__MUIM_Set(cl
, obj
, (APTR
)msg
);
786 case MUIM_SetAsString
: return Notify__MUIM_SetAsString(cl
, obj
, (APTR
)msg
);
787 case MUIM_SetUData
: return Notify__MUIM_SetUData(cl
, obj
, (APTR
)msg
);
788 case MUIM_SetUDataOnce
: return Notify__MUIM_SetUData(cl
, obj
, (APTR
)msg
); /* use Notify_SetUData */
789 case MUIM_WriteLong
: return Notify__MUIM_WriteLong(cl
, obj
, (APTR
)msg
);
790 case MUIM_WriteString
: return Notify__MUIM_WriteString(cl
, obj
, (APTR
)msg
);
791 case MUIM_ConnectParent
: return Notify__MUIM_ConnectParent(cl
,obj
,(APTR
)msg
);
792 case MUIM_DisconnectParent
: return Notify__MUIM_DisconnectParent(cl
,obj
,(APTR
)msg
);
793 case MUIM_GetConfigItem
: return Notify__MUIM_GetConfigItem(cl
,obj
,(APTR
)msg
);
796 return DoSuperMethodA(cl
, obj
, msg
);
798 BOOPSI_DISPATCHER_END
804 const struct __MUIBuiltinClass _MUI_Notify_desc
= {
805 MUIC_Notify
, /* Class name */
806 ROOTCLASS
, /* super class name */
807 sizeof(struct MUI_NotifyData
), /* size of class own datas */
808 (void*)Notify_Dispatcher
/* class dispatcher */