BWindow: Use a SplayTree to store shortcuts.
This makes for much faster lookups, and avoids the need to allocate an array. sizeof(BWindow) is unchanged (on x86_64, 504; on x86, 376) so this should not break ABI/API. Quick benchmark in Tracker: 501 lookups, before: ~488 usec 501 lookups, after: ~284 usec Change-Id: Ica2c728f0c5957380add53e14a826a4aade52df0 Reviewed-on: https://review.haiku-os.org/c/haiku/+/10720 Tested-by: Commit checker robot <[email protected]> Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
fd2113c61a
commit
ad37e9a395
@@ -381,7 +381,9 @@ private:
|
||||
uint32 _unused1;
|
||||
BMenuBar* fKeyMenuBar;
|
||||
BButton* fDefaultButton;
|
||||
BList fShortcuts;
|
||||
void* fShortcuts;
|
||||
void* _unused2;
|
||||
int32 _unused3[5];
|
||||
int32 fTopViewToken;
|
||||
bool fUpdateRequested;
|
||||
bool fOffscreen;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <Autolock.h>
|
||||
#include <Bitmap.h>
|
||||
#include <Button.h>
|
||||
#include <Debug.h>
|
||||
#include <Deskbar.h>
|
||||
#include <DirectMessageTarget.h>
|
||||
#include <FindDirectory.h>
|
||||
@@ -54,6 +55,7 @@
|
||||
#include <binary_compatibility/Interface.h>
|
||||
#include <input_globals.h>
|
||||
#include <tracker_private.h>
|
||||
#include <util/SplayTree.h>
|
||||
|
||||
|
||||
//#define DEBUG_WIN
|
||||
@@ -89,36 +91,6 @@ struct BWindow::unpack_cookie {
|
||||
};
|
||||
|
||||
|
||||
class BWindow::Shortcut {
|
||||
public:
|
||||
Shortcut(uint32 key, uint32 modifiers,
|
||||
BMenuItem* item);
|
||||
Shortcut(uint32 key, uint32 modifiers,
|
||||
BMessage* message, BHandler* target);
|
||||
~Shortcut();
|
||||
|
||||
bool Matches(uint32 key, uint32 preparedModifiers) const;
|
||||
|
||||
uint32 Key() const { return fKey; };
|
||||
uint32 Modifiers() const;
|
||||
uint32 PreparedModifiers() const { return fPreparedModifiers; };
|
||||
BMenuItem* MenuItem() const { return fMenuItem; }
|
||||
BMessage* Message() const { return fMessage; }
|
||||
BHandler* Target() const { return fTarget; }
|
||||
|
||||
static uint32 AllowedModifiers();
|
||||
static uint32 PrepareKey(uint32 key);
|
||||
static uint32 PrepareModifiers(uint32 modifiers);
|
||||
|
||||
private:
|
||||
uint32 fKey;
|
||||
uint32 fPreparedModifiers;
|
||||
BMenuItem* fMenuItem;
|
||||
BMessage* fMessage;
|
||||
BHandler* fTarget;
|
||||
};
|
||||
|
||||
|
||||
using BPrivate::gDefaultTokens;
|
||||
using BPrivate::MenuPrivate;
|
||||
|
||||
@@ -242,6 +214,73 @@ BWindow::unpack_cookie::unpack_cookie()
|
||||
// #pragma mark - BWindow::Shortcut
|
||||
|
||||
|
||||
class BWindow::Shortcut : public SplayTreeLink<BWindow::Shortcut> {
|
||||
public:
|
||||
struct TreeKey {
|
||||
uint32 key;
|
||||
uint32 prepared_modifiers;
|
||||
|
||||
TreeKey(uint32 key, uint32 preparedModifiers)
|
||||
: key(key), prepared_modifiers(preparedModifiers) {}
|
||||
};
|
||||
|
||||
struct SplayTreeDefinition {
|
||||
typedef TreeKey KeyType;
|
||||
typedef BWindow::Shortcut NodeType;
|
||||
|
||||
static KeyType GetKey(const NodeType* node)
|
||||
{
|
||||
return TreeKey(node->Key(), node->PreparedModifiers());
|
||||
}
|
||||
static SplayTreeLink<NodeType>* GetLink(NodeType* node)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
static int Compare(const KeyType& key, const NodeType* node)
|
||||
{
|
||||
return node->Compare(key.key, key.prepared_modifiers);
|
||||
}
|
||||
};
|
||||
|
||||
typedef ::SplayTree<SplayTreeDefinition> SplayTree;
|
||||
|
||||
public:
|
||||
static SplayTree* CastToTree(void** storage)
|
||||
{
|
||||
STATIC_ASSERT(sizeof(void*) == sizeof(SplayTree));
|
||||
return reinterpret_cast<SplayTree*>(storage);
|
||||
}
|
||||
|
||||
public:
|
||||
Shortcut(uint32 key, uint32 modifiers,
|
||||
BMenuItem* item);
|
||||
Shortcut(uint32 key, uint32 modifiers,
|
||||
BMessage* message, BHandler* target);
|
||||
~Shortcut();
|
||||
|
||||
int Compare(uint32 key, uint32 preparedModifiers) const;
|
||||
|
||||
uint32 Key() const { return fKey; };
|
||||
uint32 Modifiers() const;
|
||||
uint32 PreparedModifiers() const { return fPreparedModifiers; };
|
||||
BMenuItem* MenuItem() const { return fMenuItem; }
|
||||
BMessage* Message() const { return fMessage; }
|
||||
BHandler* Target() const { return fTarget; }
|
||||
|
||||
static uint32 AllowedModifiers();
|
||||
static uint32 PrepareKey(uint32 key);
|
||||
static uint32 PrepareModifiers(uint32 modifiers);
|
||||
|
||||
private:
|
||||
uint32 fKey;
|
||||
uint32 fPreparedModifiers;
|
||||
BMenuItem* fMenuItem;
|
||||
BMessage* fMessage;
|
||||
BHandler* fTarget;
|
||||
};
|
||||
|
||||
|
||||
BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMenuItem* item)
|
||||
:
|
||||
fKey(PrepareKey(key)),
|
||||
@@ -272,10 +311,14 @@ BWindow::Shortcut::~Shortcut()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BWindow::Shortcut::Matches(uint32 key, uint32 preparedModifiers) const
|
||||
int
|
||||
BWindow::Shortcut::Compare(uint32 key, uint32 preparedModifiers) const
|
||||
{
|
||||
return fKey == key && fPreparedModifiers == preparedModifiers;
|
||||
if (fKey != key)
|
||||
return fKey - key;
|
||||
if (fPreparedModifiers != preparedModifiers)
|
||||
return fPreparedModifiers - preparedModifiers;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -426,9 +469,12 @@ BWindow::~BWindow()
|
||||
delete fTopView;
|
||||
|
||||
// remove all remaining shortcuts
|
||||
int32 shortcutCount = fShortcuts.CountItems();
|
||||
for (int32 i = 0; i < shortcutCount; i++)
|
||||
delete (Shortcut*)fShortcuts.ItemAtFast(i);
|
||||
Shortcut::SplayTree* shortcuts = Shortcut::CastToTree(&fShortcuts);
|
||||
while (!shortcuts->IsEmpty()) {
|
||||
Shortcut* shortcut = shortcuts->Root();
|
||||
shortcuts->Remove(shortcut);
|
||||
delete shortcut;
|
||||
}
|
||||
|
||||
// TODO: release other dynamically-allocated objects
|
||||
free(fTitle);
|
||||
@@ -1709,7 +1755,7 @@ BWindow::_AddShortcut(uint32* _key, uint32* _modifiers, BMenuItem* item)
|
||||
*_key = shortcut->Key();
|
||||
*_modifiers = shortcut->Modifiers();
|
||||
|
||||
fShortcuts.AddItem(shortcut);
|
||||
Shortcut::CastToTree(&fShortcuts)->Insert(shortcut);
|
||||
}
|
||||
|
||||
|
||||
@@ -1733,7 +1779,7 @@ BWindow::AddShortcut(uint32 key, uint32 modifiers, BMessage* message, BHandler*
|
||||
// removes the shortcut if it already exists!
|
||||
RemoveShortcut(shortcut->Key(), shortcut->Modifiers());
|
||||
|
||||
fShortcuts.AddItem(shortcut);
|
||||
Shortcut::CastToTree(&fShortcuts)->Insert(shortcut);
|
||||
}
|
||||
|
||||
|
||||
@@ -1748,7 +1794,7 @@ void
|
||||
BWindow::RemoveShortcut(uint32 key, uint32 modifiers)
|
||||
{
|
||||
Shortcut* shortcut = _FindShortcut(key, modifiers);
|
||||
if (shortcut != NULL && fShortcuts.RemoveItem(shortcut))
|
||||
if (shortcut != NULL && Shortcut::CastToTree(&fShortcuts)->Remove(shortcut))
|
||||
delete shortcut;
|
||||
else if (key == 'Q' && modifiers == B_COMMAND_KEY)
|
||||
fNoQuitShortcut = true; // the quit shortcut is a fake shortcut
|
||||
@@ -2770,6 +2816,7 @@ BWindow::_InitData(BRect frame, const char* title, window_look look,
|
||||
fLastMouseMovedView = NULL;
|
||||
fKeyMenuBar = NULL;
|
||||
fDefaultButton = NULL;
|
||||
fShortcuts = NULL;
|
||||
|
||||
// Shortcut 'Q' is handled in _HandleKeyDown() directly, as its message
|
||||
// get sent to the application, and not one of our handlers.
|
||||
@@ -3918,13 +3965,14 @@ BWindow::_FindShortcut(uint32 key, uint32 modifiers)
|
||||
key = Shortcut::PrepareKey(key);
|
||||
uint32 preparedModifiers = Shortcut::PrepareModifiers(modifiers);
|
||||
|
||||
int32 shortcutCount = fShortcuts.CountItems();
|
||||
for (int32 index = 0; index < shortcutCount; index++) {
|
||||
Shortcut* shortcut = (Shortcut*)fShortcuts.ItemAt(index);
|
||||
if (shortcut != NULL && shortcut->Matches(key, preparedModifiers))
|
||||
return shortcut;
|
||||
}
|
||||
Shortcut::SplayTree* shortcuts = Shortcut::CastToTree(&fShortcuts);
|
||||
Shortcut* shortcut = shortcuts->FindClosest(Shortcut::TreeKey(key, preparedModifiers),
|
||||
false, true);
|
||||
|
||||
if (shortcut == NULL)
|
||||
return NULL;
|
||||
if (shortcut->Compare(key, preparedModifiers) == 0)
|
||||
return shortcut;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user