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
; /* TRUE if 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
,
113 struct MUIP_Notify
*msg
)
117 struct NotifyNode
*nnode
;
119 if ((msg
->TrigAttr
== MUIA_Window_InputEvent
)
120 && (msg
->TrigVal
!= MUIV_EveryTime
))
122 IX ix
= { IX_VERSION
};
124 if (ParseIX((CONST_STRPTR
) msg
->TrigVal
, &ix
) != 0)
128 (struct NotifyNode
*)mui_alloc_struct(struct NotifyNodeIX
)))
130 ((struct NotifyNodeIX
*)nnode
)->ix
= ix
;
135 nnode
= mui_alloc_struct(struct NotifyNode
);
141 nnode
->nn_Active
= FALSE
;
142 nnode
->nn_TrigAttr
= msg
->TrigAttr
;
143 nnode
->nn_TrigVal
= msg
->TrigVal
;
144 nnode
->nn_DestObj
= msg
->DestObj
;
145 nnode
->nn_NumParams
= msg
->FollowParams
;
147 /* Allocate one more IPTR (FollowParams + 1) as some ext apps/classes
148 forget trailing NULLs in methods like MUIM_MultiSet and MUI seems
149 like it can live with that (without crashing) */
151 paramsize
= (msg
->FollowParams
+ 1);
152 if (msg
->TrigVal
== MUIV_EveryTime
)
157 if ((nnode
->nn_Params
= (IPTR
*) mui_alloc(paramsize
* sizeof(IPTR
))))
159 IPTR
*par
= (IPTR
*) & msg
->FollowParams
;
161 for (i
= 0; i
< msg
->FollowParams
; i
++)
163 nnode
->nn_Params
[i
] = *(par
+ i
+ 1);
166 if (msg
->TrigVal
== MUIV_EveryTime
)
168 nnode
->nn_NewParams
= nnode
->nn_Params
+ msg
->FollowParams
+ 1;
169 for (i
= 0; i
< msg
->FollowParams
; i
++)
171 nnode
->nn_NewParams
[i
] = *(par
+ i
+ 1);
183 static void DeleteNNode(struct MUI_NotifyData
*data
,
184 struct NotifyNode
*nnode
)
186 mui_free(nnode
->nn_Params
);
191 IPTR
Notify__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
);
196 IPTR
Notify__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
198 struct MUI_NotifyData
*data
;
199 struct TagItem
*tags
= msg
->ops_AttrList
;
202 obj
= (Object
*) DoSuperMethodA(cl
, obj
, (Msg
) msg
);
206 data
= INST_DATA(cl
, obj
);
208 while ((tag
= NextTagItem(&tags
)) != NULL
)
213 data
->mnd_HelpLine
= (LONG
) tag
->ti_Data
;
217 data
->mnd_HelpNode
= (STRPTR
) tag
->ti_Data
;
221 data
->mnd_ObjectID
= (ULONG
) tag
->ti_Data
;
225 data
->mnd_UserData
= (IPTR
) tag
->ti_Data
;
237 IPTR
Notify__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
239 struct MinNode
*node
, *tmp
;
240 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
242 if (data
->mnd_NotifyList
)
244 for (node
= data
->mnd_NotifyList
->mlh_Head
; node
->mln_Succ
;
247 tmp
= node
->mln_Succ
;
248 DeleteNNode(data
, (struct NotifyNode
*)node
);
250 mui_free(data
->mnd_NotifyList
);
253 return DoSuperMethodA(cl
, obj
, msg
);
256 static void check_notify(NNode nnode
, Object
*obj
, struct TagItem
*tag
)
261 BOOL donotify
= FALSE
;
263 /* is it the good attribute ? */
264 if (tag
->ti_Tag
!= nnode
->nn_TrigAttr
)
267 /* Is the notification already being performed? */
268 if (nnode
->nn_Active
)
273 D(bug("Notifyloop detected! (#%d)\n", counter
++));
274 D(bug(" Source object: 0x%x", obj
));
276 switch ((IPTR
) nnode
->nn_DestObj
)
278 case MUIV_Notify_Application
:
279 D(bug(" Dest object: 0x%x (MUIV_Notify_Application)\n",
282 case MUIV_Notify_Self
:
283 D(bug(" Dest object: 0x%x (MUIV_Notify_Self)\n", obj
));
286 case MUIV_Notify_Window
:
287 if (muiRenderInfo(obj
)) /* otherwise _win(obj) does NULL access! */
289 D(bug(" Dest object: 0x%x (MUIV_Notify_Window)\n",
294 D(bug(" Dest object: INVALID "
295 "(MUIV_Notify_Window, but no muiRenderInfo)\n"));
299 D(bug(" Dest object: 0x%x\n", nnode
->nn_DestObj
));
302 D(bug(" Attribute: 0x%x Value: 0x%x\n", tag
->ti_Tag
,
309 if (nnode
->nn_TrigVal
== MUIV_EveryTime
)
313 else if (nnode
->nn_TrigAttr
== MUIA_Window_InputEvent
)
315 if (MatchIX((struct InputEvent
*)tag
->ti_Data
,
316 &((struct NotifyNodeIX
*)nnode
)->ix
))
321 else if (nnode
->nn_TrigVal
== tag
->ti_Data
)
328 switch ((IPTR
) nnode
->nn_DestObj
)
330 case MUIV_Notify_Application
:
333 case MUIV_Notify_Self
:
336 case MUIV_Notify_Window
:
337 if (muiRenderInfo(obj
)) /* otherwise _win(obj) does NULL access! */
347 destobj
= nnode
->nn_DestObj
;
350 params
= nnode
->nn_Params
;
351 if (nnode
->nn_TrigVal
== MUIV_EveryTime
)
353 params
= nnode
->nn_NewParams
;
355 for (i
= 1; i
< nnode
->nn_NumParams
; i
++)
357 switch (nnode
->nn_Params
[i
])
359 case MUIV_TriggerValue
:
360 params
[i
] = tag
->ti_Data
;
363 case MUIV_NotTriggerValue
:
364 params
[i
] = !tag
->ti_Data
;
370 nnode
->nn_Active
= TRUE
;
373 DoMethodA(destobj
, (Msg
) params
);
375 nnode
->nn_Active
= FALSE
;
382 IPTR
Notify__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
384 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
385 struct TagItem
*tags
= msg
->ops_AttrList
;
386 BOOL no_notify
= FALSE
;
388 struct MinNode
*node
;
390 /* There are many ways to find out what tag items provided by set()
391 ** we do know. The best way should be using NextTagItem() and simply
392 ** browsing through the list.
394 while ((tag
= NextTagItem(&tags
)) != NULL
)
399 data
->mnd_HelpLine
= (LONG
) tag
->ti_Data
;
403 data
->mnd_HelpNode
= (STRPTR
) tag
->ti_Data
;
407 if (tag
->ti_Data
== TRUE
)
412 data
->mnd_ObjectID
= (ULONG
) tag
->ti_Data
;
416 data
->mnd_UserData
= tag
->ti_Data
;
422 * check for notifications
424 if (!data
->mnd_NotifyList
|| no_notify
)
427 tags
= msg
->ops_AttrList
;
428 while ((tag
= NextTagItem(&tags
)))
430 for (node
= data
->mnd_NotifyList
->mlh_Head
;
431 node
->mln_Succ
; node
= node
->mln_Succ
)
433 check_notify((NNode
) node
, obj
, tag
);
444 IPTR
Notify__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
446 /* small macro to simplify return value storage */
447 #define STORE *(msg->opg_Storage)
449 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
451 //kprintf("*** Notify->GET\n");
452 switch (msg
->opg_AttrID
)
454 case MUIA_ApplicationObject
:
455 if (data
->mnd_GlobalInfo
)
456 STORE
= (IPTR
) data
->mnd_GlobalInfo
->mgi_ApplicationObject
;
461 case MUIA_AppMessage
: /* struct AppMessage ? */
466 STORE
= (IPTR
) data
->mnd_HelpLine
;
470 STORE
= (IPTR
) data
->mnd_HelpNode
;
474 STORE
= (IPTR
) data
->mnd_ObjectID
;
478 STORE
= (IPTR
) data
->mnd_ParentObject
;
486 STORE
= data
->mnd_UserData
;
494 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
499 * MUIM_CallHook : Call a standard amiga callback hook, defined by a Hook
502 IPTR
Notify__MUIM_CallHook(struct IClass
*cl
, Object
*obj
,
503 struct MUIP_CallHook
*msg
)
505 if (msg
->Hook
->h_Entry
)
506 return CallHookPkt(msg
->Hook
, obj
, &msg
->param1
);
513 * MUIM_Export : to export an objects "contents" to a dataspace object.
515 /* nothing to export */
518 * MUIM_FindUData : tests if the MUIA_UserData of the object
519 * contains the given <udata> and returns the object pointer in this case.
521 IPTR
Notify__MUIM_FindUData(struct IClass
*cl
, Object
*obj
,
522 struct MUIP_FindUData
*msg
)
524 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
526 if (data
->mnd_UserData
== msg
->udata
)
535 * MUIM_GetUData : This method tests if the MUIA_UserData of the object
536 * contains the given <udata> and gets <attr> to <storage> for itself
539 IPTR
Notify__MUIM_GetUData(struct IClass
*cl
, Object
*obj
,
540 struct MUIP_GetUData
*msg
)
542 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
544 if (data
->mnd_UserData
== msg
->udata
)
546 get(obj
, msg
->attr
, msg
->storage
);
554 * MUIM_Import : to import an objects "contents" from a dataspace object.
556 /* nothing to import */
559 * MUIM_KillNotify : kills previously given notifications on specific attributes.
561 IPTR
Notify__MUIM_KillNotify(struct IClass
*cl
, Object
*obj
,
562 struct MUIP_KillNotify
*msg
)
564 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
565 struct MinNode
*node
;
566 struct NotifyNode
*nnode
;
568 if (!data
->mnd_NotifyList
)
571 for (node
= data
->mnd_NotifyList
->mlh_Head
; node
->mln_Succ
;
572 node
= node
->mln_Succ
)
574 nnode
= (NNode
) node
;
575 if (msg
->TrigAttr
== nnode
->nn_TrigAttr
)
577 Remove((struct Node
*)node
);
578 DeleteNNode(data
, nnode
);
587 * MUIM_KillNotifyObj : originally undocumented !
588 * Supposed to kill a notification with a given attr and a given dest.
590 IPTR
Notify__MUIM_KillNotifyObj(struct IClass
*cl
, Object
*obj
,
591 struct MUIP_KillNotifyObj
*msg
)
593 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
594 struct MinNode
*node
;
595 struct NotifyNode
*nnode
;
597 if (!data
->mnd_NotifyList
)
600 for (node
= data
->mnd_NotifyList
->mlh_Head
; node
->mln_Succ
;
601 node
= node
->mln_Succ
)
603 nnode
= (NNode
) node
;
604 if ((msg
->TrigAttr
== nnode
->nn_TrigAttr
)
605 && (msg
->dest
== nnode
->nn_DestObj
))
607 Remove((struct Node
*)node
);
608 DeleteNNode(data
, nnode
);
617 * MUIM_MultiSet : Set an attribute for multiple objects.
619 IPTR
Notify__MUIM_MultiSet(struct IClass
*cl
, Object
*obj
,
620 struct MUIP_MultiSet
*msg
)
623 for (destobj_p
= (IPTR
*) & msg
->obj
; (*destobj_p
) != 0; destobj_p
++)
625 set((APTR
) *destobj_p
, msg
->attr
, msg
->val
);
632 * MUIM_NoNotifySet : Acts like MUIM_Set but doesn't trigger any notification.
634 IPTR
Notify__MUIM_NoNotifySet(struct IClass
*cl
, Object
*obj
,
635 struct MUIP_NoNotifySet
*msg
)
637 return SetAttrs(obj
, MUIA_NoNotify
, TRUE
, msg
->attr
, msg
->val
,
643 * MUIM_Notify : Add a notification event handler to an object.
645 IPTR
Notify__MUIM_Notify(struct IClass
*cl
, Object
*obj
,
646 struct MUIP_Notify
*msg
)
648 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
649 struct NotifyNode
*nnode
;
651 if (msg
->FollowParams
< 1)
654 if (data
->mnd_NotifyList
== NULL
)
656 if (!(data
->mnd_NotifyList
= mui_alloc_struct(struct MinList
)))
658 NewList((struct List
*)data
->mnd_NotifyList
);
661 nnode
= CreateNNode(data
, msg
);
665 AddTail((struct List
*)data
->mnd_NotifyList
, (struct Node
*)nnode
);
671 * MUIM_Set : Set an attribute to a value, useful within a MUIM_Notify method.
673 IPTR
Notify__MUIM_Set(struct IClass
*cl
, Object
*obj
,
674 struct MUIP_Set
*msg
)
676 return set(obj
, msg
->attr
, msg
->val
);
680 * MUIM_SetAsString : Set a (text kind) attribute to a string.
682 IPTR
Notify__MUIM_SetAsString(struct IClass
*cl
, Object
*obj
,
683 struct MUIP_SetAsString
*msg
)
689 RawDoFmt(msg
->format
, (ULONG
*) & msg
->val
,
690 (VOID_FUNC
) AROS_ASMSYMNAME(len_func
), &txt_len
);
692 /* D(bug("Notify_SetAsString: fmt=%s, txtlen=%d\n", msg->format, txt_len)); */
693 txt
= AllocVec(txt_len
+ 1, 0);
699 RawDoFmt(msg
->format
, (ULONG
*) & msg
->val
,
700 (VOID_FUNC
) AROS_ASMSYMNAME(cpy_func
), &txtptr
);
703 set(obj
, msg
->attr
, (IPTR
) txt
);
711 * MUIM_SetUData : This method tests if the MUIA_UserData of the object
712 * contains the given <udata> and sets <attr> to <val> for itself in this case.
714 IPTR
Notify__MUIM_SetUData(struct IClass
*cl
, Object
*obj
,
715 struct MUIP_SetUData
*msg
)
717 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
719 if (data
->mnd_UserData
== msg
->udata
)
721 set(obj
, msg
->attr
, msg
->val
);
729 * MUIM_WriteLong : This method simply writes a longword somewhere to memory.
731 IPTR
Notify__MUIM_WriteLong(struct IClass
*cl
, Object
*obj
,
732 struct MUIP_WriteLong
*msg
)
734 *(msg
->memory
) = msg
->val
;
740 * MUIM_WriteString : This method simply copies a string somewhere to memory.
742 IPTR
Notify__MUIM_WriteString(struct IClass
*cl
, Object
*obj
,
743 struct MUIP_WriteString
*msg
)
745 strcpy(msg
->memory
, msg
->str
);
749 /**************************************************************************
751 **************************************************************************/
752 IPTR
Notify__MUIM_ConnectParent(struct IClass
*cl
, Object
*obj
,
753 struct MUIP_ConnectParent
*msg
)
755 //struct MUI_NotifyData *data = INST_DATA(cl, obj);
757 /* Objects only have parents if they are inside a group or family object;
758 ** no idea why MUIA_Parent belongs to the notify class then
760 /* data->mnd_ParentObject = msg->parent;*/
761 muiGlobalInfo(obj
) = muiGlobalInfo(msg
->parent
);
765 /**************************************************************************
766 MUIM_DisconnectParent
767 **************************************************************************/
768 IPTR
Notify__MUIM_DisconnectParent(struct IClass
*cl
, Object
*obj
,
769 struct MUIP_DisconnectParent
*msg
)
771 //struct MUI_NotifyData *data = INST_DATA(cl, obj);
772 /* data->mnd_ParentObject = NULL;*/
774 /* Some apps (YAM) seem to access this even after disconnection */
775 muiGlobalInfo(obj
) = NULL
;
780 /**************************************************************************
782 **************************************************************************/
783 IPTR
Notify__MUIM_GetConfigItem(struct IClass
*cl
, Object
*obj
,
784 struct MUIP_GetConfigItem
*msg
)
787 DoMethod(muiGlobalInfo(obj
)->mgi_Configdata
, MUIM_Dataspace_Find
,
792 *msg
->storage
= found
;
802 BOOPSI_DISPATCHER(IPTR
, Notify_Dispatcher
, cl
, obj
, msg
)
804 switch (msg
->MethodID
)
807 return Notify__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
809 return Notify__OM_DISPOSE(cl
, obj
, msg
);
811 return Notify__OM_SET(cl
, obj
, (struct opSet
*)msg
);
813 return Notify__OM_GET(cl
, obj
, (struct opGet
*)msg
);
815 return Notify__MUIM_CallHook(cl
, obj
, (APTR
) msg
);
819 return Notify__MUIM_FindUData(cl
, obj
, (APTR
) msg
);
821 return Notify__MUIM_GetUData(cl
, obj
, (APTR
) msg
);
824 case MUIM_KillNotify
:
825 return Notify__MUIM_KillNotify(cl
, obj
, (APTR
) msg
);
826 case MUIM_KillNotifyObj
:
827 return Notify__MUIM_KillNotifyObj(cl
, obj
, (APTR
) msg
);
829 return Notify__MUIM_MultiSet(cl
, obj
, (APTR
) msg
);
830 case MUIM_NoNotifySet
:
831 return Notify__MUIM_NoNotifySet(cl
, obj
, (APTR
) msg
);
833 return Notify__MUIM_Notify(cl
, obj
, (APTR
) msg
);
835 return Notify__MUIM_Set(cl
, obj
, (APTR
) msg
);
836 case MUIM_SetAsString
:
837 return Notify__MUIM_SetAsString(cl
, obj
, (APTR
) msg
);
839 return Notify__MUIM_SetUData(cl
, obj
, (APTR
) msg
);
840 case MUIM_SetUDataOnce
:
841 return Notify__MUIM_SetUData(cl
, obj
, (APTR
) msg
);
842 /* use Notify_SetUData */
844 return Notify__MUIM_WriteLong(cl
, obj
, (APTR
) msg
);
845 case MUIM_WriteString
:
846 return Notify__MUIM_WriteString(cl
, obj
, (APTR
) msg
);
847 case MUIM_ConnectParent
:
848 return Notify__MUIM_ConnectParent(cl
, obj
, (APTR
) msg
);
849 case MUIM_DisconnectParent
:
850 return Notify__MUIM_DisconnectParent(cl
, obj
, (APTR
) msg
);
851 case MUIM_GetConfigItem
:
852 return Notify__MUIM_GetConfigItem(cl
, obj
, (APTR
) msg
);
855 return DoSuperMethodA(cl
, obj
, msg
);
857 BOOPSI_DISPATCHER_END
862 const struct __MUIBuiltinClass _MUI_Notify_desc
=
864 MUIC_Notify
, /* Class name */
865 ROOTCLASS
, /* super class name */
866 sizeof(struct MUI_NotifyData
), /* size of class own datas */
867 (void *) Notify_Dispatcher
/* class dispatcher */