English Amiga Board


Go Back   English Amiga Board > Coders > Coders. System

 
 
Thread Tools
Old 13 February 2024, 20:49   #1
PeterK
Registered User
 
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,366
Question How to emulate a WB menu item pick?

At the moment I'm writing a tool for WB 3.1 which should refresh all icon images after a screen mode change. I've done that already successfully for all disk icons and left out icons, but now I still want to emulate a click in the WB menu onto the "Rescan All" item in order to get a complete update of all icons with wrong colors on the new screen.

Therefore I've written a few test programs trying to pick a WB menu item either by using IDCMP messages or alternatively by using the input.device. In my tests I'm trying to select the "About" requester from the Workbench menu, because this gives a quick and clear response to see whether it works or not.

With IDCMP messages I couldn't find a working solution for the emulation of the right mouse buttons, not even with WFLG_RMBTRAP set.

So, I tried to find a solution by using the input.device instead. And that really works correctly as long as MagicMenu is installed. The "About" requester appears. But without MagicMenu running, the Workbench only switches the WB menu title bar on and then nothing happens anymore. The selection of icons on the screen gets blocked, too. And you can only pass through the WB menu, but trying to execute any item won't work.

There is one exception for the original WB menu too: In case that I once choose the "About" menu item manually before I try out my test program then, after that initial item selection, my test program always works and I do not even need the RMB emulation, just a selection of the item "MENU_VERSION" would be enough to get the requester.

What am I doing wrong or how can I get my test program to work without using MagicMenu? I tried already to add some calls to OnMenu(), but that didn't help to fix the WB blocking. I also tried BeginIO(), but with the same problem. DoIO() is something what I didn't try yet. I have no experience with this message system, so I probably did something stupid, but what exactly is wrong or missing in my code?
Code:
                incdir  "include:"
                include "exec/execbase.i"
                include "exec/initializers.i"
                include "dos/dos.i"
                include "dos/dosextens.i"
                include "devices/input.i"
                include "devices/inputevent.i"
                include "intuition/intuition.i"
                include "lvo/LVOs.i"

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: WBMenuInputTest 0.9",0

                CNOP    0,2

.cpuisok        MOVEA.L ThisTask(A6),A4
                LEA     pr_MsgPort(A4),A0
                LEA     RmbIOStdRequest\.mn_ReplyPort(PC),A1
                MOVE.L  A0,(A1)
                LEA     MyIOStdRequest\.mn_ReplyPort(PC),A1
                MOVE.L  A0,(A1)
                LEA     MupIOStdRequest\.mn_ReplyPort(PC),A1
                MOVE.L  A0,(A1)
                TST.L   pr_CLI(A4)              ; from CLI or WB ?
                BNE.S   .opendevice
                JSR     _LVOWaitPort(A6)        ; wait for startup
                MOVE.L  D0,-(SP)                ; save WB message
                LEA     pr_MsgPort(A4),A0
                JSR     _LVOGetMsg(A6)          ; remove Msg from port
                PEA     .replyWBmsg(PC)         ; WB patch for RTS from CLI calls
.opendevice     MOVEQ   #RETURN_ERROR,D2

                LEA     RmbIOStdRequest(PC),A2
                LEA     inputdevice(PC),A0
                MOVEA.L A2,A1
                MOVEQ   #0,D0                   ; unit 0
                MOVEQ   #0,D1                   ; no flags
                JSR     _LVOOpenDevice(A6)
                TST.B   D0
                BNE.S   .openfailed
                MOVEA.L A2,A1
                JSR     _LVOSendIO(A6)          ; right mouse button down
                MOVEA.L A2,A1
                JSR     _LVOWaitIO(A6)
                MOVEA.L A2,A1
                JSR     _LVOCloseDevice(A6)

                LEA     MyIOStdRequest(PC),A2
                LEA     inputdevice(PC),A0
                MOVEA.L A2,A1
                MOVEQ   #0,D0                   ; unit 0
                MOVEQ   #0,D1                   ; no flags
                JSR     _LVOOpenDevice(A6)
                TST.B   D0
                BNE.S   .openfailed
                MOVEA.L A2,A1
                JSR     _LVOSendIO(A6)          ; pick WB menu "Version"
                MOVEA.L A2,A1
                JSR     _LVOWaitIO(A6)
                MOVEA.L A2,A1
                JSR     _LVOCloseDevice(A6)

                LEA     MupIOStdRequest(PC),A2
                LEA     inputdevice(PC),A0
                MOVEA.L A2,A1
                MOVEQ   #0,D0                   ; unit 0
                MOVEQ   #0,D1                   ; no flags
                JSR     _LVOOpenDevice(A6)
                TST.B   D0
                BNE.S   .openfailed
                MOVEA.L A2,A1
                JSR     _LVOSendIO(A6)          ; right mouse button up
                MOVEA.L A2,A1
                JSR     _LVOWaitIO(A6)
                MOVEA.L A2,A1
                JSR     _LVOCloseDevice(A6)
                MOVEQ   #RETURN_OK,D2
.openfailed     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_VERSION    EQU	(0 & $1F) | ((5 & $3F) << 5) | (($1F & $1F) << 11)

RmbIOStdRequest
.ln_Succ        DC.L    0
.ln_Pred        DC.L    0
.ln_Type        DC.B    NT_MESSAGE
.ln_Pri         DC.B    0
.ln_Name        DC.L    0
.mn_ReplyPort   DC.L    0                       ; filled out at program start
.mn_Length      DC.W    $30                     ; size of IOStdRequest
.io_Device      DC.L    0
.io_Unit        DC.L    0
.io_Command     DC.W    IND_WRITEEVENT
.io_Flags       DC.B    0
.io_Error       DC.B    0
.io_Actual      DC.L    0
.io_Length      DC.L    $12                     ; size of InputEvent
.io_Data        DC.L    RmbInputEvent
.io_Offset      DC.L    0

RmbInputEvent
.ie_Next        DC.L    0
.ie_Class       DC.B    IECLASS_RAWMOUSE
.ie_SubClass    DC.B    IESUBCLASS_COMPATIBLE
.ie_Code        DC.W    MENUDOWN                ; emulate right mouse button down
.ie_Qualifier   DC.W    0
.ie_x           DC.W    0
.ie_y           DC.W    0
.ie_TimeStamp   DC.L    0

MyIOStdRequest
.ln_Succ        DC.L    0
.ln_Pred        DC.L    0
.ln_Type        DC.B    NT_MESSAGE
.ln_Pri         DC.B    0
.ln_Name        DC.L    0
.mn_ReplyPort   DC.L    0                       ; filled out at program start
.mn_Length      DC.W    $30                     ; size of IOStdRequest
.io_Device      DC.L    0
.io_Unit        DC.L    0
.io_Command     DC.W    IND_WRITEEVENT
.io_Flags       DC.B    0
.io_Error       DC.B    0
.io_Actual      DC.L    0
.io_Length      DC.L    $12                     ; size of InputEvent
.io_Data        DC.L    MyInputEvent
.io_Offset      DC.L    0

MyInputEvent
.ie_Next        DC.L    0
.ie_Class       DC.B    IECLASS_MENULIST
.ie_SubClass    DC.B    IESUBCLASS_COMPATIBLE
.ie_Code        DC.W    MENU_VERSION
.ie_Qualifier   DC.W    MENUDOWN                ; still right mouse button down
.ie_x           DC.W    0
.ie_y           DC.W    0
.ie_TimeStamp   DC.L    0

MupIOStdRequest
.ln_Succ        DC.L    0
.ln_Pred        DC.L    0
.ln_Type        DC.B    NT_MESSAGE
.ln_Pri         DC.B    0
.ln_Name        DC.L    0
.mn_ReplyPort   DC.L    0                       ; filled out at program start
.mn_Length      DC.W    $30                     ; size of IOStdRequest
.io_Device      DC.L    0
.io_Unit        DC.L    0
.io_Command     DC.W    IND_WRITEEVENT
.io_Flags       DC.B    0
.io_Error       DC.B    0
.io_Actual      DC.L    0
.io_Length      DC.L    $12                     ; size of InputEvent
.io_Data        DC.L    MupInputEvent
.io_Offset      DC.L    0

MupInputEvent
.ie_Next        DC.L    0
.ie_Class       DC.B    IECLASS_RAWMOUSE
.ie_SubClass    DC.B    IESUBCLASS_COMPATIBLE
.ie_Code        DC.W    MENUUP                  ; emulate right mouse button up
.ie_Qualifier   DC.W    0
.ie_x           DC.W    0
.ie_y           DC.W    0
.ie_TimeStamp   DC.L    0

inputdevice     DC.B    "input.device",0

Last edited by PeterK; 18 February 2024 at 14:56.
PeterK is offline  
Old 14 February 2024, 10:21   #2
hooverphonique
ex. demoscener "Bigmama"
 
Join Date: Jun 2012
Location: Fyn / Denmark
Posts: 1,624
Are you sure the workbench window has focus? Using input.device, whatever you do would affect the currently focused window, right!?
hooverphonique is offline  
Old 14 February 2024, 11:46   #3
PeterK
Registered User
 
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,366
Yes, that's right, I should indeed set the ACTIVE_WINDOW to Workbench before I use the menu. But I'm using the left out tool icon from the WB screen in my tests and once it worked with MagicMenu it even works that way without MagicMenu. There must be another problem being responsible for the blocking.

And no, WB 3.1 unfortunately has no Arexx port.
PeterK is offline  
Old 14 February 2024, 15:31   #4
aros-sg
Registered User
 
Join Date: Nov 2015
Location: Italy
Posts: 191
See PowerWB source code on Aminet. You can send Intuition Messages yourself (which you set up such that they come back to your own replyport you create, not back to Intuition). Possibly bonus: maybe annoy a little bit Thor by doing things like this ...
aros-sg is online now  
Old 14 February 2024, 16:01   #5
PeterK
Registered User
 
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,366
Thanks for this hint, aros-sg!

I will have a look at the PowerWB source code ASAP.

Yes, Thor probably knows best how to work with Intuition and how to get access to menus without blocking the system. He may like my attempt or not ..., I just need a working solution for WB 3.1 to rescan all icons in the open windows. And that code exists already and the user can simply execute it by selecting "Update All" in the WB menu. I even have the WB 3.1 C source for that "Rescan All", but why should I rewrite that if it can be launched by just picking the WB menu item?

Last edited by PeterK; 14 February 2024 at 16:11.
PeterK is offline  
Old 16 February 2024, 14:33   #6
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,233
Quote:
Originally Posted by hooverphonique View Post
Are you sure the workbench window has focus? Using input.device, whatever you do would affect the currently focused window, right!?
That doesn't work - the issue is that it doesn't drive the state of the intuition state machine, which can be quite delicate. The way how this works is that the input device creates "raw events" which you can also inject, and then these events all "flow downstream" through all event handlers. The intuition event handler is one of them - it "digests" the input events it recevices from the input device (or the handlers of higher priority) and then sends them down to either the IDCMP if there is an IDCMP port in a window, or to lower level priority handlers, such as the one of the console.device.

Thus, if you send an inputevent intuition would normally generate, the event will probably end up in lower handlers, but that intuition recognizes it as one of its own and sorts it into the IDCMPs I doubt since it is none of the input even types intuition would usually react upon - it is one of the types intuition would rather create.

This being said, why exactly do you think it is necessary to tell the workbench to refresh its icons if it doesn't do itself? Usually workbench knowns when the screen prefs change (or rather, IPrefs knows and forwards the information).
Thomas Richter is offline  
Old 16 February 2024, 15:35   #7
PeterK
Registered User
 
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,366
Thanks for your explanations, Thomas. I think I've to read them carefully a few more times later again to understand what really happens with my input events.

There are also some comments in the MagicMenu.guide, maybe from Olsen. The problem seems to be (from my point of view) that a right mouse button down event lets most of the system fall asleep and that can easily cause deadlocks. MagicMenu seems to take some (I don't know what?) precautions to avoid these deadlocks. I just wanted to know how they are doing that?

I will try out another modification of my code today by first sending all 3 IORequests at once in a forbid state and then after the permit start waiting for the 3 replies. I hope that by doing it this way Intuition gets the final "RMB up" request before my tasks falls asleep and the system gets blocked. If that also has no success, I may try a different approach by walking directly through the WB window structure, and I hope there is some access to the menu items somewhere under menustrip, but I didn't check that yet (just an idea from last night).

So, why do I want to refresh all the icons after a screenmode change? That's no problem under WB v44+, but the old WB 3.1 doesn't know anything about palette based icons and color mapping. It will never reload icons to remap their colors. WB v44+ is doing that by calling icon.library IconControlA() and sets the icons screen first to NULL in order to release all pens, and then remaps all icons that are stored with a GlobalScreen flag. But on WB 3.1 (my) icon.library stores no icons in its internal list, because 3.1 is still doing many things in workbench.library, like allocating memory for some DiskObject structures and freeing them later. There is no access to a list of all open WBObjects. As stated in my 1. post I've already written a program which can refresh all the disk icons and left out icons on WB, the only part that is still missing is the refresh of all icons in the open windows, because the ColorIcons are not remapped by the system. I'm glad that even WB 3.1 already has a menu function to do that. It calls the internal routine "Rescan All". Now, I just want to launch that somehow, so that the user can refresh really everything on the WB screen with only one click onto my tool. Maybe, after some user tests, I could integrate that later into icon.library, too.
PeterK is offline  
Old 16 February 2024, 16:53   #8
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,233
While I afraid that I understood only half of the first part, concerning the icon refresh - have you attempted just to change the date or touch one of the preferences files in ENV:sys? This should trigger IPrefs to pick up the change, reload the (actually unchanged) preferences, and force their installation into the workbench, which would then re-render the icons or even re-open the screen.
Thomas Richter is offline  
Old 16 February 2024, 20:09   #9
PeterK
Registered User
 
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,366
No, changing the date or overwriting a file in ENV:Sys like the screenmode.prefs will never reload any icons on WB 3.1, not even on WB v44+. On v44+ the Workbench task only remaps the icon palettes to the colors of the new screen and after a C2P icon.library creates new planar images for the ColorIcons.

The usual 4-color planar images on WB 3.1 will never need a remapping, because the first 4 pens are using the fixed system colors only, or 8 colors for MWB icons. Ok, the windows and icon images may get rearranged and redrawn after a screenmode change, but the icons are not reloaded, nor remapped. LayoutIconA() is another v44 function to do that for a new screen, used by DOpus5 for example.

Unfortunately, my tests with sending all 3 IORequests at once in a Forbid state didn't work at all, the deadlock with Forbid was even worse. And I also couldn't find a solution with the WB window menustrip data, because there seems to be no reference for the associated commands in the menu items. But that needs more investigations, I won't give up that soon ...

Btw, in my test program it's the menu pick (the 2. IORequest) which hangs. If I disable it, then RMB down and RMB up are executed without causing a deadlock. Maybe I have to supply the correct mouse position for the menu pick, too. That can be calculated from the MenuItem data, but I don't have much hope that it will fix anything. ...no, it did not!

Update: Meanwhile, I found a solution for the test tool with the "About" requester by using the shortcut key "?"+<RCommand>, but now I have to add a shortcut command for the "Update All" item to the menu. It already appears, but there are are still some problems to solve ...

Last edited by PeterK; 18 February 2024 at 14:54.
PeterK is offline  
Old 18 February 2024, 21:57   #10
PeterK
Registered User
 
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,366
All problems are solved now, as I hope.

I've rewritten my test program for the "Update all" Workbench menu, which can be used on a WB up to v45, because WB v47 has already a different menu layout (one additional item for disks). My program only does a simple check whether menu 0 item 5 looks like the "Version" entry for the "About" requester by checking the command shortcut key for being a "?". If that is not the case then the program won't do anything and just returns.

Update: the following code is not perfect yet. It needs some optimizations and improvements to work safer and more reliable under critical circumstances.

Code:
                incdir  "include:"
                include "exec/execbase.i"
                include "exec/initializers.i"
                include "dos/dos.i"
                include "dos/dosextens.i"
                include "devices/input.i"
                include "devices/inputevent.i"
                include "intuition/intuition.i"
                include "lvo/LVOs.i"

_LVOPrivateOpenLibrary  EQU -$32A               ; _LVOexecPrivate17

MENU_RESCAN_ALL EQU     (0 & $1F) | ((3 & $3F) << 5) | (($1F & $1F) << 11)

MENU_0_ITEM_5   EQU     (0 & $1F) | ((5 & $3F) << 5) | (($1F & $1F) << 11)

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: WBMenuRescanAll 1.0",0

                CNOP    0,2                     ; 2024 by Peter Keunecke

.cpuisok        MOVEA.L ThisTask(A6),A2
                LEA     pr_MsgPort(A2),A0
                LEA     DELdIOStdRequest\.mn_ReplyPort(PC),A1
                MOVE.L  A0,(A1)
                LEA     DELuIOStdRequest\.mn_ReplyPort(PC),A1
                MOVE.L  A0,(A1)
                TST.L   pr_CLI(A2)              ; from CLI or WB ?
                BNE.S   .openlibrary
                JSR     _LVOWaitPort(A6)        ; wait for startup
                MOVE.L  D0,-(SP)                ; save WB message
                LEA     pr_MsgPort(A2),A0
                JSR     _LVOGetMsg(A6)          ; remove Msg from port
                PEA     .replyWBmsg(PC)         ; WB patch for RTS from CLI calls

.openlibrary    MOVEQ   #RETURN_ERROR,D2
                MOVEQ   #3,D0
                JSR     _LVOPrivateOpenLibrary(A6)
                MOVE.L  D0,D6                   ; intuibase
                BEQ.W   .openfailed
                JSR     _LVOForbid(A6)
                LEA     WorkbenchPort(PC),A1    ; WB 3.1 has no Port in that list !
                JSR     _LVOFindPort(A6)
                MOVEQ   #RETURN_WARN,D2
                TST.L   D0                      ; Workbench MsgPort ?
                BEQ.S   .tryscreen
                MOVEA.L D0,A0
                MOVEA.L MP_SIGTASK(A0),A0       ; Workbench process
                MOVE.L  pr_WindowPtr(A0),D0     ; it may have been disabled with -1
                BGT.S   .windowptr
.tryscreen      MOVEA.L D6,A0                   ; intuibase
                MOVEA.L ib_ActiveScreen(A0),A0
                MOVE.L  sc_FirstWindow(A0),D0
.trywindow      BEQ.S   .nowindows
                MOVEA.L D0,A0
                MOVE.L  wd_Flags(A0),D1         ; check bit 25 for WFG_WBENCHWINDOW
                LSL.L   #6,D1
                BMI.S   .windowptr
                MOVE.L  (A0),D0                 ; wd_NextWindow
                BRA.S   .trywindow

.wrongmenu      MOVEA.L (4).w,A6                ; execbase
.nowindows      JSR     _LVOPermit(A6)
                BRA.W   .closelibrary

.windowptr      MOVEA.L D0,A2                   ; a Workbench window
                MOVEQ   #RETURN_ERROR,D2
                MOVEA.L A2,A0                   ; window
                MOVEA.L D6,A6                   ; intuibase
                JSR     _LVOActivateWindow(A6)
                MOVEA.L wd_MenuStrip(A2),A5     ; menu
                MOVEA.L A5,A0
                MOVE.L  #MENU_0_ITEM_5,D0       ; v47+ has a different menu layout!
                JSR     _LVOItemAddress(A6)
                MOVEA.L D0,A0                   ; is this the MenuItem "Version" ?
                CMPI.B  #"?",mi_Command(A0)     ; command = "?"  ?
                BNE.S   .wrongmenu              ; abort now, don't touch this menu
                MOVEA.L A2,A0                   ; window
                JSR     _LVOClearMenuStrip(A6)
                MOVEA.L A5,A0
                MOVE.L  #MENU_RESCAN_ALL,D0     ; let's assume item 3 is "Update all"
                JSR     _LVOItemAddress(A6)
                MOVEA.L D0,A0                   ; add flags to MenuItem "Update all"
                MOVEQ   #ITEMENABLED | COMMSEQ,D0
                OR.W    D0,mi_Flags(A0)
                MOVEQ   #$7F,D0                 ; set <DEL> as command shortcut key
                MOVE.B  D0,mi_Command(A0)       ; I hope that <DEL> is not yet in use
                MOVEA.L A2,A0                   ; window
                MOVEA.L A5,A1                   ; menu
                JSR     _LVOSetMenuStrip(A6)
                MOVEA.L (4).w,A6                ; execbase
                JSR     _LVOPermit(A6)

                LEA     inputdevice(PC),A0
                LEA     DELdIOStdRequest(PC),A1
                MOVEQ   #0,D0                   ; unit 0
                MOVEQ   #0,D1                   ; no flags
                JSR     _LVOOpenDevice(A6)
                TST.B   D0
                BNE.S   .closelibrary
                LEA     inputdevice(PC),A0
                LEA     DELuIOStdRequest(PC),A1
                MOVEQ   #0,D0                   ; unit 0
                MOVEQ   #0,D1                   ; no flags
                JSR     _LVOOpenDevice(A6)
                TST.B   D0
                BNE.S   .closedevice
                LEA     DELdIOStdRequest(PC),A1
                JSR     _LVODoIO(A6)            ; <DEL> down + RCommand
                LEA     DELuIOStdRequest(PC),A1
                JSR     _LVODoIO(A6)            ; <DEL> up
                MOVEQ   #RETURN_OK,D2
                LEA     DELuIOStdRequest(PC),A1
                JSR     _LVOCloseDevice(A6)
.closedevice    LEA     DELdIOStdRequest(PC),A1
                JSR     _LVOCloseDevice(A6)
.closelibrary   MOVEA.L D6,A1                   ; intuibase
                JSR     _LVOCloseLibrary(A6)
.openfailed     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

DELdIOStdRequest
.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    $30                     ; size of IOStdRequest
.io_Device      DC.L    0
.io_Unit        DC.L    0
.io_Command     DC.W    IND_WRITEEVENT
.io_Flags       DC.B    0
.io_Error       DC.B    0
.io_Actual      DC.L    0
.io_Length      DC.L    $12                     ; size of InputEvent
.io_Data        DC.L    DELdInputEvent
.io_Offset      DC.L    0

DELdInputEvent
.ie_Next        DC.L    0
.ie_Class       DC.B    IECLASS_RAWKEY
.ie_SubClass    DC.B    IESUBCLASS_COMPATIBLE
.ie_Code        DC.W    $0046                   ; <DEL> down
.ie_Qualifier   DC.W    IEQUALIFIER_RCOMMAND
.ie_x           DC.W    0
.ie_y           DC.W    0
.ie_TimeStamp   DC.L    0

DELuIOStdRequest
.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    $30                     ; size of IOStdRequest
.io_Device      DC.L    0
.io_Unit        DC.L    0
.io_Command     DC.W    IND_WRITEEVENT
.io_Flags       DC.B    0
.io_Error       DC.B    0
.io_Actual      DC.L    0
.io_Length      DC.L    $12                     ; size of InputEvent
.io_Data        DC.L    DELuInputEvent
.io_Offset      DC.L    0

DELuInputEvent
.ie_Next        DC.L    0
.ie_Class       DC.B    IECLASS_RAWKEY
.ie_SubClass    DC.B    IESUBCLASS_COMPATIBLE
.ie_Code        DC.W    $00C6                   ; <DEL> up
.ie_Qualifier   DC.W    0
.ie_x           DC.W    0
.ie_y           DC.W    0
.ie_TimeStamp   DC.L    0

inputdevice     DC.B    "input.device",0

WorkbenchPort   DC.B    "WORKBENCH",0

                CNOP    0,4
I've also written a complete "RefreshIcons" tool for WB 3.1, which also updates all the disks and left out icons. That will be available at my IconLib thread.

Last edited by PeterK; 22 February 2024 at 14:26.
PeterK is offline  
Old 21 February 2024, 14:21   #11
boemann
Camilla, AmigaOS Dev.
 
Join Date: Mar 2020
Location: Frederiksberg
Posts: 328
Hmm that is a very hacky solution. Did you try to do as aros-sg suggested in comment 4. That sounds like a much cleaner solution
boemann is offline  
Old 21 February 2024, 14:56   #12
PeterK
Registered User
 
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,366
What is so hacky with my solution?

I started this thread in the hope to get some useful suggestions, but there was nothing matching exactly my demands. I also checked the PowerWB code to get some inspiration, but that source looks so much different that I couldn't find a solution for my program. I already tested IDCMP messages to the window port before, but with the result that sending right mouse button events didn't work at all. And no, I don't want to create a completely new menu, I just want to access the item "Update All" in the existing WB menu. Unfortunately, the menu layout has already changed again on WB v47, and it seems to be quite difficult to check a particular menu item number for the function behind it which gets executed when the user selects that item. I guess that the menu item text is localized, so that makes it impossible to compare strings.

+++ I just found an image of the WB menu in the PowerWB package with an interesting remark about the item positions. Look at the author's comment in the attached image below. That's exactly why I added my simple check for the menu layout.

But, if you know how to write a better and more system friendly code for WB 3.1, don't hesitate to publish it here. Every suggestion that really works is welcome.

No, WB v44+ won't need a tool like my RefreshIcons, which is now available at the end of my IconLib thread:
https://eab.abime.net/showthread.php...34#post1670234
Attached Thumbnails
Click image for larger version

Name:	PowerWBMenu.png
Views:	44
Size:	10.2 KB
ID:	81706  

Last edited by PeterK; 21 February 2024 at 19:24.
PeterK is offline  
Old 22 February 2024, 11:15   #13
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,233
Quote:
Originally Posted by PeterK View Post
What is so hacky with my solution?

Multiple things. Intuition->FirstScreen is not Forbid-protected. It is protected by the intuition lock. Thus, at the time you look at this pointer, it may no longer be vaild because intuition is right now working on it. Similarly, the menu strip is also under control of its owner, namely the workbench, thus just looking at the pointer does not ensure that the pointer is actually valid at the time you check. That is, ItemAdress() may not function properly or crash in case you let it iterate over the menu of another process.
ClearMenuStrip you call without knowing whether the workbench is probably currently trying to reach out for the menu, so you may crash the workbench at this point. You also assume that the menu you are looking for is in a particular position, which may be fine enough if the workbench is really the workbench.
Thomas Richter is offline  
Old 22 February 2024, 14:57   #14
PeterK
Registered User
 
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,366
Thank you for your suggestions to make my code safer and more reliable, Thor.

Is Intuition always not Forbid() protected in general or can it simply be reactivated at any time by some interrupts, maybe a requester with a message from an interrupt popping up on the screen suddenly or similar actions?

I will try to improve my code by locking Intuition for a while and maybe the screen, too. Just a question concerning LockPubScreen("Workbench"): does that argument "Workbench" really ensure that the WB screen is returned, even if the user has renamed it already to something else. And Scout's window list also shows the name "Workbench Screen", which won't match in a string comparison with "Workbench". Can I rely on to get and lock the WB screen, whatever its actual name is?
PeterK is offline  
Old 22 February 2024, 17:52   #15
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,233
Quote:
Originally Posted by PeterK View Post
Is Intuition always not Forbid() protected in general or can it simply be reactivated at any time by some interrupts, maybe a requester with a message from an interrupt popping up on the screen suddenly or similar actions?
Not an interrupt, but a message from the input.device (which runs at prio 20) and which will reach intuition at its input event handler. To stop intuition,you use LockIBase(0). Unfortunately, this call has "other" side effects, namely that you cannot safely call *any* (well, actually, many) intuition functions. Reason being that most intuition functions are asynchronous in nature: They just "write a note" to the intuition input handler to get their job done, and then wait for the input handler to reply when it's done. Unfortunately, as IBase is locked, the input handler cannot do anything, and thus the call deadlocks.


ItemAddress() is probably fine, but ClearMenuStrip() and AddMenuStrip() are certainly *not* right because they need to interact with the input handler (ensure that no menu is picked anymore, and wait for the user to stop playing with the menu).


Also, to gain access to the workbench screen, I would use LockPubScreen() because that also ensures that the screen is not going away as long as you hold the lock.


What remains as issue is how to get hold of the intuition menu and an active workbench window.


Quote:
Originally Posted by PeterK View Post
I will try to improve my code by locking Intuition for a while and maybe the screen, too. Just a question concerning LockPubScreen("Workbench"): does that argument "Workbench" really ensure that the WB screen is returned, even if the user has renamed it already to something else. And Scout's window list also shows the name "Workbench Screen", which won't match in a string comparison with "Workbench". Can I rely on to get and lock the WB screen, whatever its actual name is?
It depends on what you want, actually. The workbench, or the default public screen? May be different if DOpus is running, for example. Given that you interact with the workbench and its internals, "Workbench" would probably be the right choice. What Scout exactly shows I do not know. Screen title maybe? That does not need to be the same.


Greetings,
Thomas
Thomas Richter is offline  
Old 23 February 2024, 15:03   #16
boemann
Camilla, AmigaOS Dev.
 
Join Date: Mar 2020
Location: Frederiksberg
Posts: 328
So neither aros-sg nor I was suggesting that you emulate mouse movements. Sending that to the idcmp port will indeed not work. But sending a IDCMP_MENUPICK to a representative window (with a replyPort to yourself) will probably work.

This will avoid you having to send a keypress or mouseevent. However wb could still be in the middle of drawing a selection, or moving an icon, which could be bad. I don't have a solution for that right now.

Checking if the menu layout is as expected can likely be done by looking at the workbench version number.

And all Thomas said is very important. But as I said wb could be in the middle of something too. What you are trying to do is by definition hacky. So at the very least try it out.
boemann is offline  
Old 23 February 2024, 15:20   #17
aros-sg
Registered User
 
Join Date: Nov 2015
Location: Italy
Posts: 191
Quote:
Originally Posted by boemann View Post
But sending a IDCMP_MENUPICK to a representative window (with a replyPort to yourself) will probably work.

It will work. I wrote PowerWB. Just try it out on 3.0 or 3.1. It extends WB by for example adding gadgets to titlebar to quickly change between "view by icon" and "view by name" or scroll with the cursor keys. It works by sending idcmp messages like IDCMP_MENUPICK or IDCMP_GADGETDOWN messages to the WB.
aros-sg is online now  
Old 23 February 2024, 15:57   #18
PeterK
Registered User
 
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,366
Quote:
Originally Posted by boemann View Post
So neither aros-sg nor I was suggesting that you emulate mouse movements. Sending that to the idcmp port will indeed not work. But sending a IDCMP_MENUPICK to a representative window (with a replyPort to yourself) will probably work.
Trying to send IDCMP_MENUPICK to im_IDCMPWindow was my very first attempt, long before I started this thread, but it didn't work. Right now, I'm looking at that code again to see what goes wrong. With SnoopDos I can see that the associated menu function is indeed executed, but then it hangs. When MagicMenu is running, I can get out of the lock by pressing the right mouse button, and then all is ok. But without MagicMenu WB stays in a deadlock. I think there is something going wrong with the reply message (I'm using my own MsgPort for mn_ReplyPort). I still have to do some more investgations. Maybe the Intuition replies on the window replyport instead or not at all?
Quote:
This will avoid you having to send a keypress or mouseevent. However wb could still be in the middle of drawing a selection, or moving an icon, which could be bad. I don't have a solution for that right now.
No, I won't expect any other mouse or keyboard events from the user in the next millisecond after he has double-clicked my tool or pressed the <Return> key in a shell. Nobody can react so fast, and why should he do something else than just waiting till the job is done?

Quote:
Checking if the menu layout is as expected can likely be done by looking at the workbench version number.
Yes, of course, but there are a lot of menu tools which are patching it as they like it. If somebody has installed such a patch and my tool does not work with that patch then it's the users problem.

Quote:
And all Thomas said is very important. But as I said wb could be in the middle of something too. What you are trying to do is by definition hacky. So at the very least try it out.
Yes, I'll try to take his advice into account and your suggestions too, but it's always more important for me to get a working solution like my RefreshIcons tool at the first step, before I then can start to improve it. My tool might be a bit hacky as most of my code, but I would never make too much efforts to write foolproof programs.
PeterK is offline  
Old 23 February 2024, 16:03   #19
PeterK
Registered User
 
Join Date: Apr 2005
Location: digital hell, Germany, after 1984, but worse
Posts: 3,366
Quote:
Originally Posted by aros-sg View Post
It will work. I wrote PowerWB. Just try it out on 3.0 or 3.1. It extends WB by for example adding gadgets to titlebar to quickly change between "view by icon" and "view by name" or scroll with the cursor keys. It works by sending idcmp messages like IDCMP_MENUPICK or IDCMP_GADGETDOWN messages to the WB.
Thank you! I will try to add that the IDCMP_GADGETDOWN message after my IDCMP_MENUPICK. Maybe it works then, because there was something missing and I could get out of the lock by pressing the right mouse button on MagicMenu.

No! IDCMP_GADGETDOWN was meant to be an alternative to IDCMP_MENUPICK, not a 2. message, and indeed you said 1. "or" 2.. My program has nothing to do with gadgets. There is still something else missing ...

Last edited by PeterK; 23 February 2024 at 18:02.
PeterK is offline  
Old 23 February 2024, 23:25   #20
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,233
Quote:
Originally Posted by PeterK View Post
Trying to send IDCMP_MENUPICK to im_IDCMPWindow was my very first attempt, long before I started this thread, but it didn't work. Right now, I'm looking at that code again to see what goes wrong.
The problem is that you do not follow the protocol. Intuition has MENUVERIFY and MENUPICK, and I would not be surprised if the workbench uses both. The protocol is that intuition first sends a MENUVERIFY if the right mouse button goes down, upon which the application can control what do to. Intuition does not yet show the menu at this point.


Typically, the workbench would then abort dragging or drawing the crawling ants, and when this message is replied, the menu is opening. Then, when the user selects a menu item, a MENUPICK is send, thus possibly seconds later (or how long it takes for the user to make a choice).



Thus, if you send a MENUPICK without a MENUVERIFY, then likely the workbench is confused. It also has a state machine driven by IDCMP events.


Now, the problem is of course that if you send a bogus MENUVERIFY upfront, you do not know whether intuition sends a real MENUVERIFY right after (or right before), and you would leave the workbench in the state of having received two of these IDCMPs, and that's again a situation that does not happen in a real system, so anything can happen, actually.


This complicated protocol is actually also the reason why MagicMenu is not (and cannot) fully work, but that's another story.


So yes, certainly, just faking an IDCMP menupick does *not* work. That's more due to the menu system protocol than actually sending a custom message to the window port.
Thomas Richter is offline  
 


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

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 17:29.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.09964 seconds with 14 queries