/* Copyright ) Darin Johnson, 1989 */ /* This file has routines to allow us to 'monitor' an Intuition port */ /* What happens, is that we create a port, myPort, and set things up */ /* so that GetMsg works normally for myPort, and the original port, */ /* winPort. However, PutMsg to myPort will put the new message */ /* on winPort, and vice-versa. Basically, the heads of both message */ /* lists are normal, but the two tails have been swapped. Since */ /* GetMsg uses the head of the list, it acts normally. PutMsg uses */ /* the tail of the list, so it acts differently. (the sigBit and */ /* sigTasks have also been swapped) */ /* What this means, is that anything PutMsg'ed to the winPort, will */ /* signal us, and we can GetMsg it. When we are finished looking at */ /* that message, we can give it to winPort by PutMsg'ing to myPort. */ #include #include #include #include #include #include #include "mymenu.h" #ifdef DO_WB extern struct MsgPort *wb_reply_port; extern int wb_cnt; #endif static struct MsgPort *winPort; static struct List *winMsgList; static LONG winSignal, our_signal; static LONG winMask; static BYTE orig_pri; /* our port */ static struct MsgPort myPort = { {NULL, NULL, NT_MSGPORT, 0, NULL}, PA_SIGNAL, 0, NULL, {NULL, NULL, NULL, NT_MESSAGE, 0} }; static struct List *myMsgList = &(myPort.mp_MsgList); /* fiddle with the two ports, setting things up */ make_MsgPort() { Forbid(); /* get the info we need */ winPort = MM->WBWindow->UserPort; winMsgList = &(winPort->mp_MsgList); winSignal = winPort->mp_SigBit; winMask = 1L << winSignal; /* setup our port */ myPort.mp_SigBit = winSignal; myPort.mp_SigTask = winPort->mp_SigTask; /* flip things around */ winPort->mp_SigTask = MM->handler_task; myMsgList->lh_Head = (struct Node *)&(winMsgList->lh_Tail); myMsgList->lh_TailPred = winMsgList->lh_TailPred; winMsgList->lh_TailPred = (struct Node *)&(myMsgList->lh_Head); myMsgList->lh_TailPred->ln_Succ = (struct Node *)&(myMsgList->lh_Tail); Permit(); /* prevent deadlocks */ orig_pri = SetTaskPri(MM->handler_task, myPort.mp_SigTask->tc_Node.ln_Pri+1); } /* Restore things the way they were before make_MsgPort() */ /* Note that we don't refer to winPort. This is because we */ /* may have had someone else 'monitor' this port (such as MonIDCMP) */ /* besides us. */ del_MsgPort() { struct Message *tmpMsg; struct MsgPort *tmpPort; Forbid(); /* clean out our list */ while ((tmpMsg = GetMsg(&myPort)) != NULL) PutMsg(&myPort, tmpMsg); /* find MsgPort that myMsgList->lh_Head belongs to */ /* (the port we've been PutMsg'ing to) */ tmpPort = (struct MsgPort *) ( (UBYTE*) &myPort - (UBYTE*) &(myPort.mp_MsgList.lh_Tail) + (UBYTE*)myMsgList->lh_Head); /* restore things */ myMsgList->lh_Head->ln_Pred = myMsgList->lh_TailPred; myMsgList->lh_TailPred->ln_Succ = myMsgList->lh_Head; tmpPort->mp_SigTask = myPort.mp_SigTask; Permit(); SetTaskPri(MM->handler_task, orig_pri); } /* do all appropriate initialization of monitor */ BOOL setup_mon() { make_MsgPort(); /* we need to allocate the same signal, so that it doesn't get allocated to something else, messing us up */ our_signal = AllocSignal(winSignal); if (our_signal != winSignal) { finish_mon(); return FALSE; } return TRUE; } /* clean up everything */ finish_mon() { del_MsgPort(); FreeSignal(our_signal); } /* See if we handle this event. If so, return ext_MenuItem structure */ struct ext_MenuItem * match_item(Class, Code) ULONG Class; USHORT Code; { register struct ext_MenuItem *tmp; if (Class != MENUPICK || Code == MENUNULL) return NULL; for (tmp = MM->item_list; tmp; tmp=tmp->next_item) if (tmp->id == Code) return tmp; return NULL; } /* The actual monitor. Just keep waiting for messages, and acting on them */ /* Note that if we don't use a certain IDCMP message, we PutMsg it to get */ /* it back to the window it was meant for. */ monitor() { register struct IntuiMessage *msg; register void *item; register ULONG mask, wb_mask; #ifdef DO_WB winMask |= (wb_mask = (1L << wb_reply_port->mp_SigBit)); #endif winMask |= SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D; while (TRUE) { mask = Wait(winMask); if (mask & SIGBREAKF_CTRL_C) { /* caught ^C, time to close up */ break; } if (mask & SIGBREAKF_CTRL_D) { /* reparse menus */ del_menu_strip(); Signal(MM->parent_task, (1 << MM->parent_sig)); Wait(SIGBREAKF_CTRL_D); add_menu_strip(); continue; } #ifdef DO_WB if (mask & wb_mask) { /* caught a reply from a WorkBench program exitting */ register struct Message *wb_msg; while ((wb_msg = GetMsg(wb_reply_port)) != NULL) { wbfree(wb_msg); wb_cnt = (wb_cnt>0 ? (wb_cnt-1) : 0); } continue; } #endif /* if we got here, we have an IDCMP message */ while ((msg = (struct IntuiMessage *)GetMsg(&myPort)) != NULL) { /* check if we deal with this or not */ if ((item=(void *)match_item(msg->Class, msg->Code))!=NULL) { ReplyMsg(msg); /* always reply */ run_item(item); /* run the indicated program */ } else { PutMsg(&myPort, msg); /* pass on to original destination */ } } } }