Re: Rebuilding menus (menuNeedsUpdate:) and System Preferences keyboard shortcuts.
Re: Rebuilding menus (menuNeedsUpdate:) and System Preferences keyboard shortcuts.
- Subject: Re: Rebuilding menus (menuNeedsUpdate:) and System Preferences keyboard shortcuts.
- From: Peter Ammon <email@hidden>
- Date: Mon, 1 Dec 2008 17:10:15 -0800
On Dec 1, 2008, at 2:17 PM, Keith Blount wrote:
Hi,
Many thanks for the reply.
If you implement menuHasKeyEquivalent:, then the menu does
not get populated for matching key equivalents; NSMenu
assumes that your code does not need it to be populated.
This puts the onus of supporting user key equivalents on the
app itself, and since there's no easy way for an app to
implement this, implementing menuHasKeyEquivalent: is not a
good idea unless the menu has custom KE handling or should
never have a KE.
I haven't found this a problem with anything except the dynamically-
created items. Everything else works fine with keyboard shortcuts
that are defined in the System Preferences.
Yes, NSMenu is a little schizophrenic about this. If you implement
menuHasKeyEquivalent:, then we will not populate the menu for key
equivalent matching; however, if you insert menu items into the menu
(either in menuNeedsUpdate: triggered by opening, or at another time)
then KEs that you assign to the menu item may still be respected.
There's no reason why this should be slow. Have you
tried profiling it with Shark? Where is its spending its
time?
Perhaps you are completely rebuilding the menu every call
to menuNeedsUpdate:. The menu state is not disturbed
between calls to menuNeedsUpdate:, so you can detect if the
user has added or deleted a style since the last update, and
if not, you do not need to do anything in menuNeedsUpdate:.
The trouble is that the styles were just an example. The application
is quite a big one, and there are a good number of menus that get
dynamically created - several of which are very likely to have
changed between calls to -menuNeedsUpdate:. For instance, my
application has a "Create Link to Document" submenu, which provides
a list of documents in the application's source list so that the
user can create links between documents. Given that the onus of the
app is on structuring and moving documents around, the order and
structure of this submenu is likely to change a lot. If I checked
for every instance of a change in state to these menus, I'd have an
awful lot of state-checking going on. And even with this state-
change checking, it would still be slower. From my understanding and
tests it seems that if -menuHasKeyEquivalent... isn't implemented,
then every time a key combo is hit, the app populates all the menus
and looks through them for the command
matching the key equivalent. This gets incredibly slow when menus
are being built dynamically - and so in my app, even with state-
change checking, there would be many occasions when certain menus
need rebuilding and thus key presses would become slower.
Sorry, that was a bit long-winded. I hope that makes sense.
The problem seems to be when the dynamic menus get built, preventing
system shortcuts from affecting them...
It's not quite as bad as "all the menus are populated for every key
combo." What is supposed to happen is, the first time a key combo is
hit, menus are populated starting from the right until a match is
found. But it also remembers the KEs for each menu, and when a
remembered KE is hit, it first populates the menu that it was last
found in. The only time it will routinely populate every menu is if a
key equivalent is not found, and users normally don't care about the
performance of unmatched key equivalents. If you're seeing different
behavior, it would be worthwhile to investigate why.
In any case, your description makes sense, but now I'm not sure what
behavior you want. In order to know if a menu has a user key
equivalent, we need to construct the menu, which means populating it;
if the menu is slow to construct then determining user key equivalents
is necessarily slow as well. Absent more information, I have two
suggestions, both of which depend on speeding up menuNeedsUpdate:
1) When you construct the menu, you can ask each item for its user key
equivalent, and cache that keyed by title. When populating a menu for
key equivalent matching, you can elide items that you previously found
to have no user key equivalent.
2) Depending on the reason for the slow menu construction, you may be
able to do less work for calls to menuNeedsUpdate: triggered for user
key equivalents, such as avoiding loading icons. I think checking to
see if the call occurs between NSMenuDidBeginTracking and
NSMenuDidEndTracking notifications should help there.
-Peter
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden