[Bug] menuBarInfo not updated correctly (only after canvas focus)

Maybe I’m overlooking something, but it seems like the menuBarInfo property of the app isn’t updated correctly.

I have a function to toggle guide visibility and would like to know the current state of the menu command, but it keeps logging the same value even though the toggling works correctly:

const toggleGuideVisibility = () => {
  const guidesVisible = getAppProperty("menuBarInfo")
    .submenu.find(c => c.menuID === 9) // View
    .submenu.find(c => c.menuID === 59) // Show
    .submenu.find(c => c.command === 3503).checked // Guides
  console.log(guidesVisible)
  performMenuCommand(3503)
}

function getAppProperty(prop) {
  return require("photoshop").action.batchPlay([
    {
      _obj: 'get',
      _target: [{ _property: prop }, { _ref: 'application', _enum: 'ordinal', _value: 'targetEnum' }],
    },
  ], { synchronousExecution: true })[0][prop]
}

function performMenuCommand(commandID: number) {
  require("photoshop").core.performMenuCommand({ commandID });
}

Some further investigation showed that the menu seems to get updated only after the canvas gets focus again.

Just noticed that there’s also the Document property guidesVisibility, however this one is also always true no matter the actual visibility of the guides :confused:

@simonhenke Did you ever find a workaround for this issue?

I have just ran into this myself, trying to query the checked state of the View > Show > Selection Edges or the View > Extras menu item.

There appears to be some sort of caching mechanism going on behind the scenes.

If I query the checked state of the menu item during an invokeCommand action event for said menu item, the menu item’s checked state never changes to accurately reflect the menu’s current state.

However, I did notice that if I move the menuBarInfo batch play into a setTimeout to give myself enough time to open ANY submenu (File, Edit, Plugin’s Flyout, etc., does not matter) with my mouse, then when the timeout occurs and the batch play executes, the menu item WILL show the correct menu item checked state.

So it seems opening the menu bar with your mouse causes PS to invalidate and repopulate the menuBarInfo cache on the next query.

The way forward may be to discover some way to programmatically invalidate this cache, if possible.

@kerrishotts Hi Kerri, are you aware of this cached menuBarInfo application property issue we seem to be encountering in this thread?

Do you know of some way to invalidate the cached object or force the property to refresh via code?

Or better yet, get to the checked menu item property more directly?

Ideally, it would be great if we could get all the menu properties (enabled, checked, visible) via the psCore.getMenuCommandState(commandID) API method instead of just enabled as it currently stands.

https://developer.adobe.com/photoshop/uxp/2022/ps_reference/media/photoshopcore/#getmenucommandstate

Would appreciate any insight you have to offer, thanks!

I also didn’t find any workaround :confused: Would be nice if the menu states would be reliable.

Im wondering if @Erin_Finnegan may have an answer to this

Bouncing this to @samgannaway

1 Like

I’ve also noticed that there are times I need to run some unnecessary getter to give Ps time to catch up to what I actually want batchPlay to do. If I run the desired batchPlay too soon, it gets ignored. However, if I throw in the getter, then the batchPlay runs expected. And (surprise!) it looks like I use this then when I’m toggling selection edges on and off.

Here’s what I found works:

let m, currentToolOptions;
    for (m = 0; m < 3; m++) {  
        currentToolOptions = await batchPlay([
            //Get the currentToolOptions to slow things down a bit 
            { "_obj": "get", "_target": [ { "_property": "currentToolOptions" }, { "_ref": "application", "_enum": "ordinal", "_value": "targetEnum" } ], "_options": { "dialogOptions": "dontDisplay" } }
        ],{ });   
    } 

So I run the getter 3 times and then Ps is finally ready and willing to toggle the selection edges appropriately.

Totally weird, but it’s a workaround that seems to work.

OK, this 3x getter should take couple of milliseconds at most. It reminded me of the old IE times, where we had to do something, that didn’t make sense at all, but it made things in JS work:

setTimeout(callback, 0)

That delay of 0 milliseconds did the magic :smiley: Would that work here?

Interestingly, I’m finding that if I manually toggle menu items by clicking them with my mouse in the Ps menu, the “menuBarInfo” for that item changes when I log it out to the console. However, when I change it programmatically with

require("photoshop").core.performMenuCommand({ commandID });

The change does not register in the console. It’s the same value.

Keyboard shortcuts to toggle the Ps menu items aren’t picked up either.

Only actually going in and using a mouse on the menu to toggle items results in a change to the “menuBarInfo” that gets logged out.

What’s even more odd is that the “checked” property appears to be the opposite of what I’d expect. When the item is manually clicked to toggle it on, checked = false when I log out the “checked” property. And, when I manually toggle it off, checked = true.

1 Like

I’m still running into this issue a year later.

Has anyone yet discovered a way to force Photoshop to invalidate and refresh its menuBarInfo application property programmatically?

Update: After hours of trying different things to invalidate menuBarInfo with no joy and finally digging through the internal UXP JavaScript for answers, I came across the following descriptor that does exactly what I need. It produces a real-time uncached status for a given menu item (commandID) including both the enabled and checked properties.

{
    _obj: 'uiInfo',
    _target: {
      _ref: 'application',
      _enum: 'ordinal',
      _value: 'targetEnum',
    },
    command: 'getCommandEnabled',
    commandID: <commandID>,
  }

Executing this in a BatchPlay returns a result similar to the following:

{
    "result": {
        "commandID": 1002,
        "enabled": true,
        "checked": true
    },
    "command": "getCommandEnabled",
    "dontRecord": true,
    "forceNotify": true
}

I don’t know if this is an undocumented descriptor or how well it is supported.
If anyone has any further information, I would like to learn more about it.

3 Likes

Are there any descriptors documented? Could you share a link to the ones that are documented? :face_with_monocle:

I suppose I meant documented in forum posts or usage examples. The only Google results I could find for uiInfo or getCommandEnabled dealt with ActionReference and Action Manager, which I believe is the legacy JSX scripting engine (pre UXP)?

For example:

1 Like

How about this? I think it should do the same thing but it is documented. https://developer.adobe.com/photoshop/uxp/2022/ps_reference/media/photoshopcore/#getmenucommandstate

get and multiGet are documented: https://developer.adobe.com/photoshop/uxp/2022/ps_reference/media/batchplay/#multi-get

Unfortunately, core.getMenuCommandState returns a single boolean representing just the enabled state of the menu item.

Sometimes you want to know if a menu item is checked instead. (e.g. View > Rulers)

Ideally they should have coded it to return both the checked and enabled states similar to the result that getCommandEnabled provides, but did not.

It’s also a bit frustrating that something called getCommandEnabled returns both checked and enabled while something called getMenuCommandState returns just enabled. The nomenclature is backwards.

Yes… when you are naming things as a programmer… you have to think 20 years ahead about all possible developments in the future because it can’t be changed later for compatibility reasons… :smiley: