From 6f759c3a7f3ea3454230aeef0c7ee40869ee0e95 Mon Sep 17 00:00:00 2001 From: Patrick Gaskin Date: Wed, 22 Apr 2020 00:57:58 -0400 Subject: [PATCH] Implemented adding menu items in hook I still need to figure out why the PLT parsing is messed up on ARM. --- src/menu.cc | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- src/menu.h | 2 +- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/menu.cc b/src/menu.cc index 27da11b..df86466 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -31,10 +31,55 @@ static QAction* (*AbstractNickelMenuController_createAction)(void*, QMenu*, QWid // a signal handler). static void (*ConfirmationDialogFactory_showOKDialog)(QString const&, QString const&); +static nmi_menu_entry_t *_entries; +static size_t _entries_n; + extern "C" MenuTextItem* AbstractNickelMenuController_createMenuTextItem_hook(void* _this, QMenu* menu, QString const& label, bool checkable, bool checked, QString const& thingy) { NMI_LOG("AbstractNickelMenuController::createMenuTextItem(%p, `%s`, %d, %d, `%s`)", menu, qPrintable(label), checkable, checked, qPrintable(thingy)); - // TODO: add items + // TODO: test on other locales + bool ismm, isrm; + if ((ismm = label == "Help" && !checkable)) + NMI_LOG("Intercepting main menu (label=Help, checkable=false)..."); + if ((isrm = label == "Dictionary" && !checkable)) + NMI_LOG("Intercepting reader menu (label=Dictionary, checkable=false)..."); + + bool add[_entries_n]; + for (size_t i = 0; i < _entries_n; i++) { + nmi_menu_entry_t *ent = &_entries[i]; + switch (_entries[i].loc) { + case NMI_MENU_LOCATION_MAIN_MENU: + add[i] = ismm; + case NMI_MENU_LOCATION_READER_MENU: + add[i] = isrm; + } + } + + for (size_t i = 0; i < _entries_n; i++) { + nmi_menu_entry_t *ent = &_entries[i]; + if (add[i]) { + NMI_LOG("Adding item '%s'...", ent->lbl); + + QString lbl(ent->lbl); + MenuTextItem* item = AbstractNickelMenuController_createMenuTextItem_orig(_this, menu, lbl, false, false, ""); + QAction* action = AbstractNickelMenuController_createAction(_this, menu, item, true, true, false); + + // note: we're capturing by value, i.e. the pointer to the global variable, rather then the stack variable, so this is safe + QObject::connect(action, &QAction::triggered, std::function([ent](bool checked){ + NMI_LOG("Item '%s' pressed...", ent->lbl); + char *err; + if (ent->execute(ent->arg, &err) && err) { + NMI_LOG("Got error %s, displaying...", err); + QString title("nickel-menu-inject"); + QString text(err); + ConfirmationDialogFactory_showOKDialog(title, text); + free(err); + return; + } + NMI_LOG("Success!", err); + })); + } + } return AbstractNickelMenuController_createMenuTextItem_orig(_this, menu, label, checkable, checked, thingy); } @@ -53,7 +98,8 @@ extern "C" int nmi_menu_hook(void *libnickel, nmi_menu_entry_t *entries, size_t reinterpret_cast(AbstractNickelMenuController_createMenuTextItem_orig) = nmi_dlhook(libnickel, "_ZN28AbstractNickelMenuController18createMenuTextItemEP5QMenuRK7QStringbbS4_", reinterpret_cast(AbstractNickelMenuController_createMenuTextItem_hook), &err); NMI_ASSERT(AbstractNickelMenuController_createMenuTextItem_orig, "failed to hook _ZN28AbstractNickelMenuController18createMenuTextItemEP5QMenuRK7QStringbbS4_: %s", err); + _entries = entries; + _entries_n = entries_n; + #undef NMI_ERR_RET } - -// TODO \ No newline at end of file diff --git a/src/menu.h b/src/menu.h index bfcfa97..2c1b3ee 100644 --- a/src/menu.h +++ b/src/menu.h @@ -22,7 +22,7 @@ typedef struct { // and returns 0 on success, or 1 with err_out (if provided) set to the malloc'd // error message on error. The provided configuration and all pointers it // references must remain valid for the lifetime of the program (i.e. not stack -// allocated). +// allocated). It MUST NOT be called more than once. int nmi_menu_hook(void *libnickel, nmi_menu_entry_t *entries, size_t entries_n, char **err_out); #ifdef __cplusplus