Tracker: Allow add-ons to dynamically extend popup menu.

An add-on may now add custom entries to the popup menu, in order
to provide more than one action.

Change-Id: Ib4726c0c1e70c59e3ba4d752df24b76cfee1c4a4
This commit is contained in:
Hrishi Hiraskar
2018-07-19 14:00:48 +00:00
committed by waddlesplash
parent d632c685a0
commit bc8427c522
4 changed files with 155 additions and 23 deletions
+7 -2
View File
@@ -7,8 +7,13 @@
struct entry_ref;
class BMessage;
class BMenu;
class BHandler;
extern "C" void process_refs(entry_ref directory, BMessage* refs,
void* reserved);
extern "C" {
void process_refs(entry_ref directory, BMessage* refs, void* reserved);
void populate_menu(BMessage* msg, BMenu* menu, BHandler* handler);
void message_received(BMessage* msg);
}
#endif // _TRACKER_ADDON_H
+1
View File
@@ -69,6 +69,7 @@ enum {
B_ZOOM = '_WZM',
B_COLORS_UPDATED = '_CLU',
B_FONTS_UPDATED = '_FNU',
B_TRACKER_ADDON_MESSAGE = '_TAM',
_APP_MENU_ = '_AMN',
_BROWSER_MENUS_ = '_BRM',
_MENU_EVENT_ = '_MEV',
+141 -20
View File
@@ -178,9 +178,100 @@ CompareLabels(const BMenuItem* item1, const BMenuItem* item2)
} // namespace BPrivate
static int32
AddOnMenuGenerate(const entry_ref* addonRef, BMenu* menu,
BContainerWindow* window)
{
BEntry entry(addonRef);
BPath path;
status_t result = entry.InitCheck();
if (result != B_OK)
return result;
result = entry.GetPath(&path);
if (result != B_OK)
return result;
image_id addonImage = load_add_on(path.Path());
if (addonImage < 0)
return addonImage;
void (*populateMenu)(BMessage*, BMenu*, BHandler*);
result = get_image_symbol(addonImage, "populate_menu", 2,
(void**)&populateMenu);
if (result < 0) {
PRINT(("Couldn't find populate_menu\n"));
unload_add_on(addonImage);
return result;
}
BMessage* message = window->AddOnMessage(B_TRACKER_ADDON_MESSAGE);
message->AddRef("addon_ref", addonRef);
// call add-on code
(*populateMenu)(message, menu, window->PoseView());
unload_add_on(addonImage);
return B_OK;
}
static status_t
RunAddOnMessageThread(BMessage *message, void *)
{
entry_ref addonRef;
BEntry entry;
BPath path;
status_t result = message->FindRef("addon_ref", &addonRef);
if (result != B_OK)
goto end;
entry = BEntry(&addonRef);
result = entry.InitCheck();
if (result != B_OK)
goto end;
result = entry.GetPath(&path);
if (result != B_OK)
goto end;
image_id addonImage = load_add_on(path.Path());
if (addonImage < 0) {
result = addonImage;
goto end;
}
void (*messageReceived)(BMessage*);
result = get_image_symbol(addonImage, "message_received", 2,
(void**)&messageReceived);
if (result < 0) {
PRINT(("Couldn't find populate_menu\n"));
unload_add_on(addonImage);
goto end;
}
// call add-on code
(*messageReceived)(message);
unload_add_on(addonImage);
return B_OK;
end:
BString buffer(B_TRANSLATE("Error %error loading add-On %name."));
buffer.ReplaceFirst("%error", strerror(result));
buffer.ReplaceFirst("%name", addonRef.name);
BAlert* alert = new BAlert("", buffer.String(), B_TRANSLATE("Cancel"),
0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
return result;
}
static bool
AddOneAddon(const Model* model, const char* name, uint32 shortcut,
uint32 modifiers, bool primary, void* context)
uint32 modifiers, bool primary, void* context,
BContainerWindow* window, BMenu* menu)
{
AddOneAddonParams* params = (AddOneAddonParams*)context;
@@ -190,6 +281,9 @@ AddOneAddon(const Model* model, const char* name, uint32 shortcut,
ModelMenuItem* item = new ModelMenuItem(model, name, message,
(char)shortcut, modifiers);
const entry_ref* addonRef = model->EntryRef();
AddOnMenuGenerate(addonRef, menu, window);
if (primary)
params->primaryList->AddItem(item);
else
@@ -1613,6 +1707,12 @@ BContainerWindow::MessageReceived(BMessage* message)
}
break;
case B_TRACKER_ADDON_MESSAGE:
{
_PassMessageToAddOn(message);
break;
}
case B_OBSERVER_NOTICE_CHANGE:
{
int32 observerWhat;
@@ -2981,8 +3081,9 @@ BContainerWindow::AddTrashContextMenus(BMenu* menu)
void
BContainerWindow::EachAddon(bool (*eachAddon)(const Model*, const char*,
uint32 shortcut, uint32 modifiers, bool primary, void* context),
void* passThru, BStringList& mimeTypes)
uint32 shortcut, uint32 modifiers, bool primary, void* context,
BContainerWindow* window, BMenu* menu),
void* passThru, BStringList& mimeTypes, BMenu* menu)
{
AutoLock<LockingList<AddonShortcut> > lock(fAddonsList);
if (lock.IsLocked()) {
@@ -3029,7 +3130,7 @@ BContainerWindow::EachAddon(bool (*eachAddon)(const Model*, const char*,
}
}
((eachAddon)(item->model, item->model->Name(), item->key,
item->modifiers, primary, passThru));
item->modifiers, primary, passThru, this, menu));
}
}
}
@@ -3062,22 +3163,22 @@ BContainerWindow::BuildMimeTypeList(BStringList& mimeTypes)
void
BContainerWindow::BuildAddOnMenu(BMenu* menu)
BContainerWindow::BuildAddOnMenu(BMenu* parentMenu)
{
BMenuItem* item = menu->FindItem(B_TRANSLATE("Add-ons"));
if (menu->IndexOf(item) == 0) {
BMenuItem* item = parentMenu->FindItem(B_TRANSLATE("Add-ons"));
if (parentMenu->IndexOf(item) == 0) {
// the folder of the context menu seems to be named "Add-Ons"
// so we just take the last menu item, which is correct if not
// build with debug option
item = menu->ItemAt(menu->CountItems() - 1);
item = parentMenu->ItemAt(parentMenu->CountItems() - 1);
}
if (item == NULL)
return;
BFont font;
menu->GetFont(&font);
parentMenu->GetFont(&font);
menu = item->Submenu();
BMenu* menu = item->Submenu();
if (menu == NULL)
return;
@@ -3102,7 +3203,7 @@ BContainerWindow::BuildAddOnMenu(BMenu* menu)
// build a list of the MIME types of the selected items
EachAddon(AddOneAddon, &params, mimeTypes);
EachAddon(AddOneAddon, &params, mimeTypes, parentMenu);
primaryList.SortItems(CompareLabels);
secondaryList.SortItems(CompareLabels);
@@ -3256,6 +3357,26 @@ BContainerWindow::UpdateMenu(BMenu* menu, UpdateMenuContext context)
}
BMessage*
BContainerWindow::AddOnMessage(int32 what)
{
BMessage* message = new BMessage(what);
// add selected refs to message
BObjectList<BPose>* selectionList = PoseView()->SelectionList();
int32 index = 0;
BPose* pose;
while ((pose = selectionList->ItemAt(index++)) != NULL)
message->AddRef("refs", pose->TargetModel()->EntryRef());
message->AddRef("dir_ref", TargetModel()->EntryRef());
message->AddMessenger("TrackerViewToken", BMessenger(PoseView()));
return message;
}
void
BContainerWindow::LoadAddOn(BMessage* message)
{
@@ -3276,15 +3397,7 @@ BContainerWindow::LoadAddOn(BMessage* message)
}
// add selected refs to message
BMessage* refs = new BMessage(B_REFS_RECEIVED);
BObjectList<BPose>* selectionList = PoseView()->SelectionList();
int32 index = 0;
BPose* pose;
while ((pose = selectionList->ItemAt(index++)) != NULL)
refs->AddRef("refs", pose->TargetModel()->EntryRef());
refs->AddMessenger("TrackerViewToken", BMessenger(PoseView()));
BMessage* refs = AddOnMessage(B_REFS_RECEIVED);
LaunchInNewThread("Add-on", B_NORMAL_PRIORITY, &AddOnThread, refs,
addonRef, *TargetModel()->EntryRef());
@@ -3342,6 +3455,14 @@ BContainerWindow::_AddFolderIcon()
}
void
BContainerWindow::_PassMessageToAddOn(BMessage* message)
{
LaunchInNewThread("Add-on-Pass-Message", B_NORMAL_PRIORITY,
&RunAddOnMessageThread, new BMessage(*message), (void*)NULL);
}
BMenuItem*
BContainerWindow::NewAttributeMenuItem(const char* label, const char* name,
int32 type, float width, int32 align, bool editable, bool statField)
+6 -1
View File
@@ -189,7 +189,11 @@ public:
// add-on iteration
void EachAddon(bool (*)(const Model*, const char*, uint32 shortcut,
uint32 modifiers, bool primary, void*), void*, BStringList&);
uint32 modifiers, bool primary, void*, BContainerWindow*, BMenu*),
void*, BStringList&, BMenu*);
BMessage* AddOnMessage(int32);
entry_ref GetCurrentDirRef();
BPopUpMenu* ContextMenu();
@@ -342,6 +346,7 @@ private:
void _UpdateSelectionMIMEInfo();
void _AddFolderIcon();
void _PassMessageToAddOn(BMessage*);
};