diff --git a/headers/os/interface/Window.h b/headers/os/interface/Window.h index 9599f04ee0..65c9444305 100644 --- a/headers/os/interface/Window.h +++ b/headers/os/interface/Window.h @@ -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; diff --git a/src/kits/interface/Window.cpp b/src/kits/interface/Window.cpp index 2bb6f06ace..b27f9faa42 100644 --- a/src/kits/interface/Window.cpp +++ b/src/kits/interface/Window.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ #include #include #include +#include //#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 { +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* GetLink(NodeType* node) + { + return node; + } + + static int Compare(const KeyType& key, const NodeType* node) + { + return node->Compare(key.key, key.prepared_modifiers); + } + }; + + typedef ::SplayTree SplayTree; + +public: + static SplayTree* CastToTree(void** storage) + { + STATIC_ASSERT(sizeof(void*) == sizeof(SplayTree)); + return reinterpret_cast(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; }