24 February 2024, 09:44 | #21 |
Registered User
Join Date: Nov 2015
Location: Italy
Posts: 201
|
Sigh ... it does work. There's no menu verify involved. What I forgot to mention was that the MenuItem whose activation you want to emulate needs to have it's item->NextSelect set to MENUNULL (as seen in PowerWB sources). The following definitely works:
Code:
#include <intuition/intuitionbase.h> #include <proto/exec.h> #include <proto/intuition.h> #include <stdio.h> #define MENU FULLMENUNUM(0,5,NOSUB) // about menu struct Screen *scr; struct Window *win; struct Menu *menu; struct MenuItem *item; struct ExtIntuiMessage imsg; struct MsgPort *replymp; int main(void) { scr = IntuitionBase->ActiveScreen; if (!scr) return 0; win = scr->FirstWindow; while(win) { if ((win->Flags & WFLG_BORDERLESS) && (win->Flags & WFLG_WBENCHWINDOW)) break; win = win->NextWindow; } if (!win) return 0; menu = win->MenuStrip; if (menu) item = ItemAddress(menu, MENU); if (!item) return 0; replymp = CreateMsgPort(); if (!replymp) return 0; item->NextSelect = MENUNULL; imsg.eim_IntuiMessage.Class = IDCMP_MENUPICK; imsg.eim_IntuiMessage.Code = MENU; imsg.eim_IntuiMessage.IDCMPWindow = win; imsg.eim_IntuiMessage.ExecMessage.mn_ReplyPort = replymp; PutMsg(win->UserPort, &imsg.eim_IntuiMessage.ExecMessage); WaitPort(replymp); DeleteMsgPort(replymp); } |
24 February 2024, 10:31 | #22 |
Coder/webmaster/gamer
Join Date: Oct 2001
Location: Canberra/Australia
Posts: 2,711
|
|
24 February 2024, 14:25 | #23 | |
Registered User
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,394
|
Quote:
So my new code for "Update all", which is still not completely done, looks like this now: Code:
incdir "include:" include "exec/execbase.i" include "exec/initializers.i" include "exec/memory.i" include "dos/dos.i" include "dos/dosextens.i" include "intuition/intuition.i" include "workbench/workbench.i" include "lvo/LVOs.i" _LVOPrivateOpenLibrary EQU -$32A ; _LVOexecPrivate17 main MOVEA.L (4).w,A6 ; execbase BTST.B #AFB_68020,AttnFlags+1(A6) BNE.S .cpuisok MOVEQ #RETURN_FAIL,D0 RTS DC.B "$VER: WBMenuTest 1.1",0 CNOP 0,2 ; 2024 by Peter Keunecke .cpuisok MOVEA.L ThisTask(A6),A0 LEA pr_MsgPort(A0),A5 TST.L pr_CLI(A0) ; from CLI or WB ? BNE.S .openlibs MOVEA.L A5,A0 ; pr_MsgPort JSR _LVOWaitPort(A6) ; wait for startup MOVE.L D0,-(SP) ; save WB message MOVEA.L A5,A0 ; pr_MsgPort JSR _LVOGetMsg(A6) ; remove Msg from port PEA .replyWBmsg(PC) ; WB patch for RTS from CLI calls .openlibs MOVEQ #RETURN_ERROR,D2 MOVEQ #3,D0 JSR _LVOPrivateOpenLibrary(A6) MOVE.L D0,D6 ; intuibase BEQ.W .itfailure MOVEQ #0,D0 ; LockNumber MOVEA.L D6,A6 ; intuibase JSR _LVOLockIBase(A6) MOVE.L D0,D7 MOVEA.L ib_ActiveScreen(A6),A0 MOVE.L sc_FirstWindow(A0),D0 .trywindow BEQ.S .returnnow MOVEA.L D0,A2 MOVE.L wd_Flags(A2),D1 ; check bit 25 for WFG_WBENCHWINDOW LSL.L #6,D1 BMI.S .windowptr MOVE.L (A2),D0 ; wd_NextWindow BRA.S .trywindow .returnnow MOVEA.L D7,A0 ; lock on IBase JSR _LVOUnlockIBase(A6) BRA.W .closelibs .windowptr MOVE.L wd_MenuStrip(A2),D0 ; first menu in WB menu strip BEQ.S .returnnow MOVEA.L D0,A3 ; A3 = menu strip = menu 0 MOVE.L mu_FirstItem(A3),D0 ; item 0 ? BEQ.S .returnnow MOVEQ #3,D1 .nextitem MOVEA.L D0,A4 ; item 0 - 3 MOVE.L (A4),D0 ; next ? BEQ.S .returnnow DBRA D1,.nextitem ; A4 = item 3 should be "Update all" MOVEA.L D0,A0 ; item 4 MOVE.L (A0),D0 ; item 5 ? BEQ.S .returnnow MOVEA.L D0,A0 ; is item 5 the "RescanAll" command CMPI.B #"?",mi_Command(A0) ; with the "?" as a shortcut key ? BNE.S .returnnow ; if not, we won't touch this menu LEA MsgMenuRescanAll\.im_IDCMPWindow(PC),A0 MOVE.L A2,(A0) ; IDCMPWindow = Workbench WindowPtr MOVEA.L (4).w,A6 ; execbase JSR _LVOForbid(A6) MOVEA.L D7,A0 ; lock on IBase MOVEA.L D6,A6 ; intuibase JSR _LVOUnlockIBase(A6) MOVEA.L A2,A0 ; WB window JSR _LVOClearMenuStrip(A6) ORI.W #MENUENABLED,mu_Flags(A3) ORI.W #ITEMENABLED,mi_Flags(A4) MOVE.W #MENUNULL,mi_NextSelect(A4) ; this was set to NULL by the OS MOVEA.L A2,A0 ; WB window MOVEA.L A3,A1 ; menu strip JSR _LVOSetMenuStrip(A6) MOVEA.L A2,A0 ; WB window JSR _LVOActivateWindow(A6) LEA MsgMenuRescanAll\.mn_ReplyPort(PC),A0 MOVE.L A5,(A0) ; pr_MsgPort MOVEA.L wd_UserPort(A2),A0 ; IDCMP receiver for Workbench LEA MsgMenuRescanAll(PC),A1 ; message: MENUPICK, MENU_RESCAN_ALL MOVEA.L (4).w,A6 ; execbase JSR _LVOPutMsg(A6) JSR _LVOPermit(A6) MOVEA.L A5,A0 ; pr_MsgPort JSR _LVOWaitPort(A6) ; wait for reply from Workbench MOVEA.L A5,A0 ; pr_MsgPort JSR _LVOGetMsg(A6) ; remove Msg from port MOVEQ #RETURN_OK,D2 .closelibs MOVEA.L D6,A1 ; intuibase JSR _LVOCloseLibrary(A6) .itfailure MOVE.L D2,D0 RTS ; CLI ends here, on WB to .replyWBmsg .replyWBmsg JSR _LVOForbid(A6) MOVEA.L (SP)+,A1 JSR _LVOReplyMsg(A6) ; WB unloads seglist MOVE.L D2,D0 ; set the final RC RTS ; return from WB tool MENU_RESCAN_ALL EQU (0 & $1F) | ((3 & $3F) << 5) | (($1F & $1F) << 11) MsgMenuRescanAll .ln_Succ DC.L 0 .ln_Pred DC.L 0 .ln_Type DC.B 0 .ln_Pri DC.B 0 .ln_Name DC.L 0 .mn_ReplyPort DC.L 0 ; filled out at program start .mn_Length DC.W $34 .im_Class DC.L IDCMP_MENUPICK .im_Code DC.W MENU_RESCAN_ALL ; Menu 0, Item 3, NoSub .im_Qualifier DC.W 0 .im_IAddress DC.L 0 .im_MouseX DC.W 0 .im_MouseY DC.W 0 .im_Seconds DC.L 0 .im_Micros DC.L 0 .im_IDCMPWindow DC.L 0 ; a WBENCHWINDOW .im_SpecialLink DC.L 0 CNOP 0,4 @Thomas Richter: Important! You have PM, please read it! Of course, I've checked the WB window flags for MENUVERIFY and other verifications, because with these flags set Intuition would ask the user first, before it would start any action on MENUPICK. No, there are no such flags set, but maybe I should check that in my code, too. Last edited by PeterK; 24 February 2024 at 21:00. |
|
24 February 2024, 20:15 | #24 |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,489
|
Problem is - this idea is also not without quirks as two processes now potentially access the same data structure (namely the menu item) in parallel. menu->NextSelect is initialized and updated when intuition displays the menu and the user left-clicks multiple elements. A LockIBase() will block out intuition from doing so, but see above.
From what I know, wb 3.1 *does* use MENUVERIFY, or at least temporarily when dragging icons or drawing a frame to multi-select icons. The IDCMP flags can be changed anytime, and thus a quick check with the debugger cannot tell you whether a particular IDCMP is actually used or not. |
24 February 2024, 21:33 | #25 |
Registered User
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,394
|
Yes, mi_NextSelect should be changed by Intuition when the user selects multiple menu elements, but nevertheless it seems to be wrong initialized by the OS before the very first access to a menu item is ever made. And that's a very old OS bug IMHO.
And no, usually there is no flag MENUVERIFY set in general, not even under 3.1, and if it were, it would probably cause some unnecessary slowdown. Ok, maybe there are temporary MENUVERIFY events, but all my menu handling is done in far less than a millisecond, so don't get paranoid. The worst thing that could happen is that my program aborts its operation. After finding a typo in my code where SetMenuStrip() is called, with A0=A5=0 instead of A0=A3 containing the menu strip pointer, I wonder why that SMS was running successfully (returning 1) and I did not even get an enforcer hit. The menu was detached by ClearMenuStrip(), then the data was modified and finally it could, for sure, not be linked into the window structure again by SetMenuStrip(window, NULL), but all was working as if nothing went wrong??? Very strange. Is ClearMenuStrip() not really detaching the data and changing mi_NextSelect works even without SetMenuStrip()? Last edited by PeterK; 24 February 2024 at 21:54. |
24 February 2024, 22:37 | #26 | ||||
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,489
|
Quote:
Quote:
Quote:
Quote:
If you modify it from outside, you do not know exactly whether the menu is currently attached, or - possibly - in the state of being teared down. In the latter case, you write into stale memory, even though at the time you looked at the menu of the window, the pointer *seemed* valid. In general, writing into structures whose lifetime is not under your control is not such a great idea. |
||||
24 February 2024, 23:37 | #27 | |||||
Registered User
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,394
|
Quote:
Quote:
Quote:
Quote:
Quote:
|
|||||
25 February 2024, 07:47 | #28 | ||||
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,489
|
Quote:
Quote:
Quote:
Quote:
1) LockPubScreen("Workbench"...) This ensures that the workbench screen is not going away while you look. (Provable by the interface definition of LockPubScreen()) 2) LockIBase(). This ensures that the window list is not going to change and menu is not just going away. 3) Walk the window list of the screen and find a workbench window. Nothing can happen now as the list is stable. 4) Find the menu in the window, and also walk that menu to the item you want to locate. This is *likely* going to work as in principle the owner of the window could possibly remove it manually there. Though the workbench is playing nicely with the system, this *should* be ok. 5) Check whether MENUVERIFY is requested. If so, skip the next two steps as this is a message you cannot generate so easily. 6) Play with NextSelect, and set it to MENUNULL. (This is where things can possibly go wrong, see below). 7) PutMsg() your fake IDCMP to the message port. DO NOT WAIT FOR REPLY. 8) Unlock IBbase. 9) Unlock the screen. 10) Wait for the message to come back. Even this algorithm has a race condition because after you unlock IBase, intuition may overwrite NextSelect. This should hopefully not do too much harm, in worst case the item contains the next selected menu item and the workbench will process both of them. There is at least no race that follows invalid pointers and will crash the system. It would certainly be better because we would have a more stable system then. Sure, 3.1 has plenty of bugs, but it doesn't get better by adding more to them. |
||||
25 February 2024, 09:15 | #29 | |
Registered User
Join Date: Nov 2015
Location: Italy
Posts: 201
|
Quote:
- User multiselects "Render" -> "Save" - User selects "Render" "Save" selection can get lost/forgotten. Slow/non responsive program may end up with two IDCMP_MENUPICK msgs in the queue and Intuition (because of user asynchronously accessing the menus) may modify item->nextselect while program has not yet done (or is in the middle of) handling the first menupick message. Other things in Intuition are not 100 % safe either. Like string gadgets. User may asynchronously (in input.device task) modify string buffer contents, while programs is in the middle of accesing/reading the exact same buffer |
|
25 February 2024, 10:04 | #30 | |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,489
|
Quote:
Again, sure, that can happen, but nothing will hang or crash if this happens. You get a half-edited string in worst case. Not a desaster. An alternative design would have been to copy the string into the IDCMP message, but that's neither a great design as you now need to dispose this memory again at some point. |
|
25 February 2024, 13:48 | #31 | |
Registered User
Join Date: Nov 2015
Location: Italy
Posts: 201
|
Quote:
Sure? If a stringgadget contains "12345678" and the program tries to read buffer and while doing that (it is at char "6") the buffer is modified to "1234" in input.device task (maybe through "Undo". stringadgets can have undobuffers) can it be sure that there is still a trailing 0-byte somewhere that will prevent it from reading past the string buffer size? The undo buffer may be "1234\0" and contain trash after that and what if the undo buffer is copied over to the string buffer using copymem() instead of strcpy() ... |
|
25 February 2024, 23:49 | #32 |
Registered User
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,394
|
Tried to take all the suggestions for a safer and more system friendly code into account now, and I'm glad that it still works.
Code:
incdir "include:" include "exec/execbase.i" include "exec/initializers.i" include "exec/memory.i" include "dos/dos.i" include "dos/dosextens.i" include "intuition/intuition.i" include "workbench/workbench.i" include "lvo/LVOs.i" _LVOPrivateOpenLibrary EQU -$32A ; _LVOexecPrivate17 main MOVEA.L (4).w,A6 ; execbase BTST.B #AFB_68020,AttnFlags+1(A6) BNE.S .cpuisok MOVEQ #RETURN_FAIL,D0 RTS DC.B "$VER: WBMenuTest 1.2",0 CNOP 0,2 ; 2024 by Peter Keunecke .cpuisok MOVEA.L ThisTask(A6),A0 LEA pr_MsgPort(A0),A5 TST.L pr_CLI(A0) ; from CLI or WB ? BNE.S .openlibs MOVEA.L A5,A0 ; pr_MsgPort JSR _LVOWaitPort(A6) ; wait for startup MOVE.L D0,-(SP) ; save WB message MOVEA.L A5,A0 ; pr_MsgPort JSR _LVOGetMsg(A6) ; remove Msg from port PEA .replyWBmsg(PC) ; WB patch for RTS from CLI calls .openlibs MOVEQ #RETURN_ERROR,D2 MOVEQ #3,D0 JSR _LVOPrivateOpenLibrary(A6) MOVE.L D0,D5 ; intuibase BEQ.W .itfailure LEA WBPubScreenName(PC),A0 ; "Workbench" MOVEA.L D5,A6 ; intuibase JSR _LVOLockPubScreen(A6) MOVE.L D0,D6 BEQ.W .wbfailure MOVEQ #0,D0 ; LockNumber JSR _LVOLockIBase(A6) MOVE.L D0,D7 MOVEA.L D6,A0 ; WB screen MOVE.L sc_FirstWindow(A0),D0 .trywindow BEQ.S .returnnow MOVEA.L D0,A2 MOVE.L wd_Flags(A2),D0 ; check bit 25 for WFG_WBENCHWINDOW LSL.L #6,D0 BMI.S .windowptr MOVE.L (A2),D0 ; wd_NextWindow BRA.S .trywindow .returnnow MOVEA.L D7,A0 ; lock on IBase JSR _LVOUnlockIBase(A6) BRA.W .unlockpub .windowptr MOVE.L wd_IDCMPFlags(A2),D0 LSL.W #2,D0 ; check bit 13 for IDCMP_MENUVERIFY BMI.S .returnnow MOVE.L wd_MenuStrip(A2),D0 ; first menu in WB menu strip BEQ.S .returnnow MOVEA.L D0,A3 ; A3 = menu strip = menu 0 MOVE.L mu_FirstItem(A3),D0 ; item 0 ? BEQ.S .returnnow MOVEQ #3,D1 .nextitem MOVEA.L D0,A4 ; item 0 - 3 MOVE.L (A4),D0 ; next ? BEQ.S .returnnow DBRA D1,.nextitem ; A4 = item 3 should be "Update all" MOVEA.L D0,A0 ; item 4 MOVE.L (A0),D0 ; item 5 ? BEQ.S .returnnow MOVEA.L D0,A0 ; is item 5 "Version, Copyright ..." CMPI.B #"?",mi_Command(A0) ; with the "?" as a shortcut key ? BNE.S .returnnow ; if not, we won't touch this menu LEA MsgMenuRescanAll\.im_IDCMPWindow(PC),A0 MOVE.L A2,(A0) ; IDCMPWindow = Workbench WindowPtr MOVEA.L (4).w,A6 ; execbase JSR _LVOForbid(A6) MOVEA.L D7,A0 ; lock on IBase MOVEA.L D5,A6 ; intuibase JSR _LVOUnlockIBase(A6) MOVEA.L A2,A0 ; WB window JSR _LVOClearMenuStrip(A6) ORI.W #MENUENABLED,mu_Flags(A3) ORI.W #ITEMENABLED,mi_Flags(A4) MOVE.W #MENUNULL,mi_NextSelect(A4) ; this was set to NULL by the OS MOVEA.L A2,A0 ; WB window MOVEA.L A3,A1 ; menu strip JSR _LVOSetMenuStrip(A6) MOVEA.L A2,A0 ; WB window JSR _LVOActivateWindow(A6) LEA MsgMenuRescanAll\.mn_ReplyPort(PC),A0 MOVE.L A5,(A0) ; pr_MsgPort MOVEA.L wd_UserPort(A2),A0 ; IDCMP receiver for Workbench LEA MsgMenuRescanAll(PC),A1 ; message: MENUPICK, MENU_RESCAN_ALL MOVEA.L (4).w,A6 ; execbase JSR _LVOPutMsg(A6) JSR _LVOPermit(A6) MOVEA.L A5,A0 ; pr_MsgPort JSR _LVOWaitPort(A6) ; wait for reply from Workbench MOVEA.L A5,A0 ; pr_MsgPort JSR _LVOGetMsg(A6) ; remove Msg from port MOVEQ #RETURN_OK,D2 .unlockpub SUBA.L A0,A0 ; no screen name supplied MOVEA.L D6,A1 ; WB screen from lock MOVEA.L D5,A6 ; intuibase JSR _LVOUnlockPubScreen(A6) .wbfailure MOVEA.L D5,A1 ; intuibase MOVEA.L (4).w,A6 ; execbase JSR _LVOCloseLibrary(A6) .itfailure MOVE.L D2,D0 RTS ; CLI ends here, on WB to .replyWBmsg .replyWBmsg JSR _LVOForbid(A6) MOVEA.L (SP)+,A1 JSR _LVOReplyMsg(A6) ; WB unloads seglist MOVE.L D2,D0 ; set the final RC RTS ; return from WB tool MENU_RESCAN_ALL EQU (0 & $1F) | ((3 & $3F) << 5) | (($1F & $1F) << 11) MsgMenuRescanAll .ln_Succ DC.L 0 .ln_Pred DC.L 0 .ln_Type DC.B 0 .ln_Pri DC.B 0 .ln_Name DC.L 0 .mn_ReplyPort DC.L 0 ; filled out at program start .mn_Length DC.W $34 .im_Class DC.L IDCMP_MENUPICK .im_Code DC.W MENU_RESCAN_ALL ; Menu 0, Item 3, NoSub .im_Qualifier DC.W 0 .im_IAddress DC.L 0 .im_MouseX DC.W 0 .im_MouseY DC.W 0 .im_Seconds DC.L 0 .im_Micros DC.L 0 .im_IDCMPWindow DC.L 0 ; a WBENCHWINDOW .im_SpecialLink DC.L 0 WBPubScreenName DC.B "Workbench",0 CNOP 0,4 |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Commodity that adds list of windows to WB menu? | coldacid | request.Apps | 6 | 25 June 2020 15:24 |
ClassicWB Scalos Menu - Item Renaming | Heywood | project.ClassicWB | 1 | 26 June 2019 15:50 |
Simplest way of creating a menu in WB? | Foebane | support.Apps | 8 | 22 September 2018 19:46 |
IBrowse custom contextual menu item | _amigan | support.Apps | 0 | 30 November 2012 17:13 |
scalos/wb top menu | _psy | project.ClassicWB | 3 | 03 January 2011 13:32 |
|
|