* Implemented support for node monitoring - you can now be notified when new
translators are installed via BTranslatorRoster::StartWatching(). * Fixed GetTranslatorData() - some hooks are only optional (this puts the JPEG, GIF, and some other translators back into the game). * Made BTranslatorRoster::Default() thread-safe. * Improved documentation. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17267 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
5ec797a76f
commit
783f7f20bd
|
@ -66,6 +66,8 @@ enum {
|
|||
B_ACQUIRE_OVERLAY_LOCK = '_AOV',
|
||||
B_SCREEN_CHANGED = '_SCH',
|
||||
B_VALUE_CHANGED = '_VCH',
|
||||
B_TRANSLATOR_ADDED = '_ART',
|
||||
B_TRANSLATOR_REMOVED = '_RRT',
|
||||
B_VIEW_MOVED = '_VMV',
|
||||
B_VIEW_RESIZED = '_VRS',
|
||||
B_WINDOW_MOVED = '_WMV',
|
||||
|
|
|
@ -27,11 +27,28 @@
|
|||
#include <String.h>
|
||||
#include <TranslatorRoster.h>
|
||||
|
||||
#include <set>
|
||||
#include <new>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
class QuarantineTranslatorImage {
|
||||
public:
|
||||
QuarantineTranslatorImage(BTranslatorRoster::Private& privateRoster);
|
||||
~QuarantineTranslatorImage();
|
||||
|
||||
void Put(const entry_ref& ref);
|
||||
void Remove();
|
||||
|
||||
private:
|
||||
BTranslatorRoster::Private& fRoster;
|
||||
entry_ref fRef;
|
||||
bool fRemove;
|
||||
};
|
||||
|
||||
} // namespace BPrivate
|
||||
|
||||
// Extensions used in the extension BMessage, defined in TranslatorFormats.h
|
||||
char B_TRANSLATOR_EXT_HEADER_ONLY[] = "/headerOnly";
|
||||
char B_TRANSLATOR_EXT_DATA_ONLY[] = "/dataOnly";
|
||||
|
@ -49,9 +66,57 @@ char B_TRANSLATOR_EXT_SOUND_LOOP[] = "nois/loop";
|
|||
BTranslatorRoster* BTranslatorRoster::sDefaultRoster = NULL;
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
/*!
|
||||
The purpose of this class is to put a translator entry_ref into - and remove
|
||||
it from the list of translators on destruction (if Remove() was called before).
|
||||
|
||||
This is used in Private::CreateTranslators() in case a translator hides a
|
||||
previous one (ie. if you install a translator in the user's translators directory
|
||||
that has the same name as one in the system's directory, it will hide this
|
||||
entry).
|
||||
*/
|
||||
QuarantineTranslatorImage::QuarantineTranslatorImage(BTranslatorRoster::Private& privateRoster)
|
||||
:
|
||||
fRoster(privateRoster),
|
||||
fRemove(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QuarantineTranslatorImage::~QuarantineTranslatorImage()
|
||||
{
|
||||
if (fRef.device == -1 || !fRemove)
|
||||
return;
|
||||
|
||||
fRoster.RemoveTranslators(fRef);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
QuarantineTranslatorImage::Put(const entry_ref& ref)
|
||||
{
|
||||
fRef = ref;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
QuarantineTranslatorImage::Remove()
|
||||
{
|
||||
fRemove = true;
|
||||
}
|
||||
|
||||
} // namespace BPrivate
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
BTranslatorRoster::Private::Private()
|
||||
: BHandler("translator roster"), BLocker("translator list"),
|
||||
fNextID(1)
|
||||
fNextID(1),
|
||||
fLazyScanning(true)
|
||||
{
|
||||
// we're sneaking us into the BApplication
|
||||
if (be_app != NULL)
|
||||
|
@ -99,9 +164,99 @@ BTranslatorRoster::Private::MessageReceived(BMessage* message)
|
|||
{
|
||||
switch (message->what) {
|
||||
case B_NODE_MONITOR:
|
||||
{
|
||||
BAutolock locker(this);
|
||||
|
||||
printf("translator roster node monitor: ");
|
||||
message->PrintToStream();
|
||||
|
||||
int32 opcode;
|
||||
if (message->FindInt32("opcode", &opcode) != B_OK)
|
||||
return;
|
||||
|
||||
switch (opcode) {
|
||||
case B_ENTRY_CREATED:
|
||||
{
|
||||
const char* name;
|
||||
node_ref nodeRef;
|
||||
if (message->FindInt32("device", &nodeRef.device) != B_OK
|
||||
|| message->FindInt64("directory", &nodeRef.node) != B_OK
|
||||
|| message->FindString("name", &name) != B_OK)
|
||||
break;
|
||||
|
||||
// TODO: make this better (possible under Haiku)
|
||||
snooze(100000);
|
||||
// let the font be written completely before trying to open it
|
||||
|
||||
_EntryAdded(nodeRef, name);
|
||||
break;
|
||||
}
|
||||
|
||||
case B_ENTRY_MOVED:
|
||||
{
|
||||
// has the entry been moved into a monitored directory or has
|
||||
// it been removed from one?
|
||||
const char* name;
|
||||
node_ref toNodeRef;
|
||||
node_ref fromNodeRef;
|
||||
node_ref nodeRef;
|
||||
|
||||
if (message->FindInt32("device", &nodeRef.device) != B_OK
|
||||
|| message->FindInt64("to directory", &toNodeRef.node) != B_OK
|
||||
|| message->FindInt64("from directory", (int64 *)&fromNodeRef.node) != B_OK
|
||||
|| message->FindInt64("node", (int64 *)&nodeRef.node) != B_OK
|
||||
|| message->FindString("name", &name) != B_OK)
|
||||
break;
|
||||
|
||||
fromNodeRef.device = nodeRef.device;
|
||||
toNodeRef.device = nodeRef.device;
|
||||
|
||||
// Do we know this one yet?
|
||||
translator_item* item = _FindTranslator(nodeRef);
|
||||
if (item == NULL) {
|
||||
// it's a new one!
|
||||
if (_IsKnownDirectory(toNodeRef))
|
||||
_EntryAdded(nodeRef, name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_IsKnownDirectory(toNodeRef)) {
|
||||
// translator got removed
|
||||
_RemoveTranslators(&nodeRef);
|
||||
break;
|
||||
}
|
||||
|
||||
// the name may have changed
|
||||
item->ref.set_name(name);
|
||||
item->ref.directory = toNodeRef.node;
|
||||
|
||||
if (_IsKnownDirectory(fromNodeRef)
|
||||
&& _IsKnownDirectory(toNodeRef)) {
|
||||
// TODO: we should rescan for the name, there might be name
|
||||
// clashes with translators in other directories
|
||||
// (as well as old ones revealed)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_ENTRY_REMOVED:
|
||||
{
|
||||
node_ref nodeRef;
|
||||
uint64 directoryNode;
|
||||
if (message->FindInt32("device", &nodeRef.device) != B_OK
|
||||
|| message->FindInt64("directory", (int64 *)&directoryNode) != B_OK
|
||||
|| message->FindInt64("node", &nodeRef.node) != B_OK)
|
||||
break;
|
||||
|
||||
translator_item* item = _FindTranslator(nodeRef);
|
||||
if (item != NULL)
|
||||
_RemoveTranslators(&nodeRef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
BHandler::MessageReceived(message);
|
||||
|
@ -129,6 +284,13 @@ BTranslatorRoster::Private::AddDefaultPaths()
|
|||
}
|
||||
|
||||
|
||||
/*!
|
||||
Adds the colon separated list of directories to the roster.
|
||||
|
||||
Note, the order in which these directories are added to actually matters,
|
||||
translators with the same name will be taken from the earlier directory
|
||||
first. See _CompareTranslatorDirectoryPriority().
|
||||
*/
|
||||
status_t
|
||||
BTranslatorRoster::Private::AddPaths(const char* paths)
|
||||
{
|
||||
|
@ -168,6 +330,12 @@ BTranslatorRoster::Private::AddPaths(const char* paths)
|
|||
}
|
||||
|
||||
|
||||
/*!
|
||||
Adds a new directory to the roster.
|
||||
|
||||
Note, the order in which these directories are added to actually matters,
|
||||
see AddPaths().
|
||||
*/
|
||||
status_t
|
||||
BTranslatorRoster::Private::AddPath(const char* path, int32* _added)
|
||||
{
|
||||
|
@ -181,8 +349,12 @@ BTranslatorRoster::Private::AddPath(const char* path, int32* _added)
|
|||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
// do we know this directory already?
|
||||
if (_IsKnownDirectory(nodeRef))
|
||||
return B_OK;
|
||||
|
||||
if (Looper() != NULL) {
|
||||
// watch these directories
|
||||
// watch that directory
|
||||
watch_node(&nodeRef, B_WATCH_DIRECTORY, this);
|
||||
}
|
||||
|
||||
|
@ -209,13 +381,14 @@ BTranslatorRoster::Private::AddPath(const char* path, int32* _added)
|
|||
|
||||
status_t
|
||||
BTranslatorRoster::Private::AddTranslator(BTranslator* translator,
|
||||
image_id image = -1, const entry_ref* ref = NULL)
|
||||
image_id image = -1, const entry_ref* ref = NULL, ino_t node = 0)
|
||||
{
|
||||
BAutolock locker(this);
|
||||
|
||||
translator_item item;
|
||||
item.translator = translator;
|
||||
item.image = image;
|
||||
item.node = node;
|
||||
if (ref != NULL)
|
||||
item.ref = *ref;
|
||||
|
||||
|
@ -231,6 +404,13 @@ BTranslatorRoster::Private::AddTranslator(BTranslator* translator,
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
BTranslatorRoster::Private::RemoveTranslators(entry_ref& ref)
|
||||
{
|
||||
_RemoveTranslators(NULL, &ref);
|
||||
}
|
||||
|
||||
|
||||
BTranslator*
|
||||
BTranslatorRoster::Private::FindTranslator(translator_id id)
|
||||
{
|
||||
|
@ -262,26 +442,45 @@ BTranslatorRoster::Private::GetTranslatorData(image_id image, translator_data& d
|
|||
|| get_image_symbol(image, "inputFormats", B_SYMBOL_TYPE_DATA, (void**)&data.input_formats) < B_OK
|
||||
|| get_image_symbol(image, "outputFormats", B_SYMBOL_TYPE_DATA, (void**)&data.output_formats) < B_OK
|
||||
|| get_image_symbol(image, "Identify", B_SYMBOL_TYPE_TEXT, (void**)&data.identify_hook) < B_OK
|
||||
|| get_image_symbol(image, "Translate", B_SYMBOL_TYPE_TEXT, (void**)&data.translate_hook) < B_OK
|
||||
|| get_image_symbol(image, "MakeConfig", B_SYMBOL_TYPE_TEXT, (void**)&data.make_config_hook) < B_OK
|
||||
|| get_image_symbol(image, "GetConfigMessage", B_SYMBOL_TYPE_TEXT, (void**)&data.get_config_message_hook) < B_OK)
|
||||
|| get_image_symbol(image, "Translate", B_SYMBOL_TYPE_TEXT, (void**)&data.translate_hook) < B_OK)
|
||||
return B_BAD_TYPE;
|
||||
|
||||
data.version = *version;
|
||||
|
||||
// those calls are optional
|
||||
get_image_symbol(image, "MakeConfig", B_SYMBOL_TYPE_TEXT, (void**)&data.make_config_hook);
|
||||
get_image_symbol(image, "GetConfigMessage", B_SYMBOL_TYPE_TEXT, (void**)&data.get_config_message_hook);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BTranslatorRoster::Private::CreateTranslators(const entry_ref& ref, int32& count)
|
||||
BTranslatorRoster::Private::CreateTranslators(const entry_ref& ref, int32& count,
|
||||
BMessage* update)
|
||||
{
|
||||
BAutolock locker(this);
|
||||
|
||||
if (_FindTranslator(ref.name) != NULL) {
|
||||
// keep the existing add-on
|
||||
return B_OK;
|
||||
BPrivate::QuarantineTranslatorImage quarantine(*this);
|
||||
|
||||
const translator_item* item = _FindTranslator(ref.name);
|
||||
if (item != NULL) {
|
||||
// check if the known translator has a higher priority
|
||||
if (_CompareTranslatorDirectoryPriority(item->ref, ref) <= 0) {
|
||||
// keep the existing add-on
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// replace existing translator(s) if the new translator succeeds
|
||||
quarantine.Put(item->ref);
|
||||
}
|
||||
|
||||
BEntry entry(&ref);
|
||||
node_ref nodeRef;
|
||||
status_t status = entry.GetNodeRef(&nodeRef);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
BPath path(&ref);
|
||||
image_id image = load_add_on(path.Path());
|
||||
if (image < B_OK)
|
||||
|
@ -290,7 +489,7 @@ BTranslatorRoster::Private::CreateTranslators(const entry_ref& ref, int32& count
|
|||
// Function pointer used to create post R4.5 style translators
|
||||
BTranslator *(*makeNthTranslator)(int32 n, image_id you, uint32 flags, ...);
|
||||
|
||||
status_t status = get_image_symbol(image, "make_nth_translator",
|
||||
status = get_image_symbol(image, "make_nth_translator",
|
||||
B_SYMBOL_TYPE_TEXT, (void**)&makeNthTranslator);
|
||||
if (status == B_OK) {
|
||||
// If the translator add-on supports the post R4.5
|
||||
|
@ -299,7 +498,9 @@ BTranslatorRoster::Private::CreateTranslators(const entry_ref& ref, int32& count
|
|||
BTranslator* translator = NULL;
|
||||
int32 created = 0;
|
||||
for (int32 n = 0; (translator = makeNthTranslator(n, image, 0)) != NULL; n++) {
|
||||
if (AddTranslator(translator, image, &ref) == B_OK) {
|
||||
if (AddTranslator(translator, image, &ref, nodeRef.node) == B_OK) {
|
||||
if (update)
|
||||
update->AddInt32("translator_id", translator->fID);
|
||||
count++;
|
||||
created++;
|
||||
} else {
|
||||
|
@ -310,6 +511,8 @@ BTranslatorRoster::Private::CreateTranslators(const entry_ref& ref, int32& count
|
|||
|
||||
if (created == 0)
|
||||
unload_add_on(image);
|
||||
|
||||
quarantine.Remove();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
@ -326,11 +529,14 @@ BTranslatorRoster::Private::CreateTranslators(const entry_ref& ref, int32& count
|
|||
}
|
||||
|
||||
if (status == B_OK)
|
||||
status = AddTranslator(translator, image, &ref);
|
||||
status = AddTranslator(translator, image, &ref, nodeRef.node);
|
||||
|
||||
if (status == B_OK)
|
||||
if (status == B_OK) {
|
||||
if (update)
|
||||
update->AddInt32("translator_id", translator->fID);
|
||||
quarantine.Remove();
|
||||
count++;
|
||||
else
|
||||
} else
|
||||
unload_add_on(image);
|
||||
|
||||
return status;
|
||||
|
@ -346,6 +552,14 @@ BTranslatorRoster::Private::StartWatching(BMessenger target)
|
|||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (fLazyScanning) {
|
||||
fLazyScanning = false;
|
||||
// Since we now have someone to report to, we cannot lazily
|
||||
// adopt changes to the translator any longer
|
||||
|
||||
_RescanChanged();
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
@ -358,6 +572,9 @@ BTranslatorRoster::Private::StopWatching(BMessenger target)
|
|||
while (iterator != fMessengers.end()) {
|
||||
if (*iterator == target) {
|
||||
fMessengers.erase(iterator);
|
||||
if (fMessengers.empty())
|
||||
fLazyScanning = true;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
@ -395,6 +612,8 @@ BTranslatorRoster::Private::Identify(BPositionIO* source,
|
|||
{
|
||||
BAutolock locker(this);
|
||||
|
||||
_RescanChanged();
|
||||
|
||||
TranslatorMap::const_iterator iterator = fTranslators.begin();
|
||||
float bestWeight = 0.0f;
|
||||
|
||||
|
@ -438,6 +657,8 @@ BTranslatorRoster::Private::GetTranslators(BPositionIO* source,
|
|||
{
|
||||
BAutolock locker(this);
|
||||
|
||||
_RescanChanged();
|
||||
|
||||
int32 arraySize = fTranslators.size();
|
||||
translator_info* array = new (std::nothrow) translator_info[arraySize];
|
||||
if (array == NULL)
|
||||
|
@ -483,6 +704,8 @@ BTranslatorRoster::Private::GetAllTranslators(translator_id** _ids, int32* _coun
|
|||
{
|
||||
BAutolock locker(this);
|
||||
|
||||
_RescanChanged();
|
||||
|
||||
int32 arraySize = fTranslators.size();
|
||||
translator_id* array = new (std::nothrow) translator_id[arraySize];
|
||||
if (array == NULL)
|
||||
|
@ -552,6 +775,34 @@ BTranslatorRoster::Private::_CompareSupport(const void* _a, const void* _b)
|
|||
}
|
||||
|
||||
|
||||
/*!
|
||||
In lazy mode, freshly installed translator are not scanned immediately
|
||||
when they become available. Instead, they are put into a set.
|
||||
|
||||
When a method is called that may be interested in these new translators,
|
||||
they are scanned on the fly. Since lazy mode also means that this roster
|
||||
does not have any listeners, we don't need to notify anyone about those
|
||||
changes.
|
||||
*/
|
||||
void
|
||||
BTranslatorRoster::Private::_RescanChanged()
|
||||
{
|
||||
EntryRefSet::iterator iterator = fRescanEntries.begin();
|
||||
|
||||
while (iterator != fRescanEntries.end()) {
|
||||
int32 count;
|
||||
CreateTranslators(*iterator, count);
|
||||
|
||||
fRescanEntries.erase(iterator);
|
||||
iterator++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Tests if the hints provided for a source stream are compatible to
|
||||
the formats the translator exports.
|
||||
*/
|
||||
const translation_format*
|
||||
BTranslatorRoster::Private::_CheckHints(const translation_format* formats,
|
||||
int32 formatsCount, uint32 hintType, const char* hintMIME)
|
||||
|
@ -607,6 +858,187 @@ BTranslatorRoster::Private::_FindTranslator(const char* name) const
|
|||
}
|
||||
|
||||
|
||||
const translator_item*
|
||||
BTranslatorRoster::Private::_FindTranslator(entry_ref& ref) const
|
||||
{
|
||||
if (ref.name == NULL)
|
||||
return NULL;
|
||||
|
||||
TranslatorMap::const_iterator iterator = fTranslators.begin();
|
||||
|
||||
while (iterator != fTranslators.end()) {
|
||||
const translator_item& item = iterator->second;
|
||||
if (item.ref == ref)
|
||||
return &item;
|
||||
|
||||
iterator++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
translator_item*
|
||||
BTranslatorRoster::Private::_FindTranslator(node_ref& nodeRef)
|
||||
{
|
||||
if (nodeRef.device < 0)
|
||||
return NULL;
|
||||
|
||||
TranslatorMap::iterator iterator = fTranslators.begin();
|
||||
|
||||
while (iterator != fTranslators.end()) {
|
||||
translator_item& item = iterator->second;
|
||||
if (item.ref.device == nodeRef.device
|
||||
&& item.node == nodeRef.node)
|
||||
return &item;
|
||||
|
||||
iterator++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Directories added to the roster have a certain priority - the first entry
|
||||
to be added has the highest priority; if a translator with the same name
|
||||
is to be found in two directories, the one with the higher priority is
|
||||
chosen.
|
||||
*/
|
||||
int32
|
||||
BTranslatorRoster::Private::_CompareTranslatorDirectoryPriority(const entry_ref& a,
|
||||
const entry_ref& b) const
|
||||
{
|
||||
// priority is determined by the order in the list
|
||||
|
||||
node_ref nodeRefA;
|
||||
nodeRefA.device = a.device;
|
||||
nodeRefA.node = a.directory;
|
||||
|
||||
node_ref nodeRefB;
|
||||
nodeRefB.device = b.device;
|
||||
nodeRefB.node = b.directory;
|
||||
|
||||
NodeRefList::const_iterator iterator = fDirectories.begin();
|
||||
|
||||
while (iterator != fDirectories.end()) {
|
||||
if (*iterator == nodeRefA)
|
||||
return -1;
|
||||
if (*iterator == nodeRefB)
|
||||
return 1;
|
||||
|
||||
iterator++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BTranslatorRoster::Private::_IsKnownDirectory(const node_ref& nodeRef) const
|
||||
{
|
||||
NodeRefList::const_iterator iterator = fDirectories.begin();
|
||||
|
||||
while (iterator != fDirectories.end()) {
|
||||
if (*iterator == nodeRef)
|
||||
return true;
|
||||
|
||||
iterator++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BTranslatorRoster::Private::_RemoveTranslators(const node_ref* nodeRef, const entry_ref* ref)
|
||||
{
|
||||
if (ref == NULL && nodeRef == NULL)
|
||||
return;
|
||||
|
||||
TranslatorMap::iterator iterator = fTranslators.begin();
|
||||
BMessage update(B_TRANSLATOR_REMOVED);
|
||||
image_id image = -1;
|
||||
|
||||
while (iterator != fTranslators.end()) {
|
||||
const translator_item& item = iterator->second;
|
||||
if ((ref != NULL && item.ref == *ref)
|
||||
|| (nodeRef != NULL && item.ref.device == nodeRef->device
|
||||
&& item.node == nodeRef->node)) {
|
||||
item.translator->fOwningRoster = NULL;
|
||||
// if the translator is busy, we don't want to be notified
|
||||
// about the removal later on
|
||||
item.translator->Release();
|
||||
image = item.image;
|
||||
update.AddInt32("translator_id", iterator->first);
|
||||
|
||||
fTranslators.erase(iterator);
|
||||
}
|
||||
|
||||
iterator++;
|
||||
}
|
||||
|
||||
// Unload image from the removed translator
|
||||
|
||||
if (image >= B_OK)
|
||||
unload_add_on(image);
|
||||
|
||||
_NotifyListeners(update);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BTranslatorRoster::Private::_EntryAdded(const node_ref& nodeRef, const char* name)
|
||||
{
|
||||
entry_ref ref;
|
||||
ref.device = nodeRef.device;
|
||||
ref.directory = nodeRef.node;
|
||||
ref.set_name(name);
|
||||
|
||||
_EntryAdded(ref);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
In lazy mode, the entry is marked to be rescanned on next use of any
|
||||
translation method (that could make use of it).
|
||||
In non-lazy mode, the translators for this entry are created directly
|
||||
and listeners notified.
|
||||
|
||||
Called by the node monitor handling.
|
||||
*/
|
||||
void
|
||||
BTranslatorRoster::Private::_EntryAdded(const entry_ref& ref)
|
||||
{
|
||||
BEntry entry;
|
||||
if (entry.SetTo(&ref) != B_OK || !entry.IsFile())
|
||||
return;
|
||||
|
||||
if (fLazyScanning) {
|
||||
fRescanEntries.insert(ref);
|
||||
return;
|
||||
}
|
||||
|
||||
BMessage update(B_TRANSLATOR_ADDED);
|
||||
int32 count = 0;
|
||||
CreateTranslators(ref, count, &update);
|
||||
|
||||
_NotifyListeners(update);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BTranslatorRoster::Private::_NotifyListeners(BMessage& update) const
|
||||
{
|
||||
MessengerList::const_iterator iterator = fMessengers.begin();
|
||||
|
||||
while (iterator != fMessengers.end()) {
|
||||
(*iterator).SendMessage(&update);
|
||||
iterator++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
|
@ -677,14 +1109,32 @@ BTranslatorRoster::Instantiate(BMessage* from)
|
|||
BTranslatorRoster *
|
||||
BTranslatorRoster::Default()
|
||||
{
|
||||
// TODO: This code isn't thread safe
|
||||
static int32 lock = 0;
|
||||
|
||||
if (sDefaultRoster != NULL)
|
||||
return sDefaultRoster;
|
||||
|
||||
if (atomic_add(&lock, 1) != 0) {
|
||||
// Just wait for the default translator to be instantiated
|
||||
while (sDefaultRoster == NULL)
|
||||
snooze(10000);
|
||||
|
||||
atomic_add(&lock, -1);
|
||||
return sDefaultRoster;
|
||||
}
|
||||
|
||||
// If the default translators have not been loaded,
|
||||
// create a new BTranslatorRoster for them, and load them.
|
||||
if (sDefaultRoster == NULL) {
|
||||
sDefaultRoster = new BTranslatorRoster();
|
||||
sDefaultRoster->AddTranslators(NULL);
|
||||
BTranslatorRoster* roster = new BTranslatorRoster();
|
||||
roster->AddTranslators(NULL);
|
||||
|
||||
sDefaultRoster = roster;
|
||||
// this will unlock any other threads waiting for
|
||||
// the default roster to become available
|
||||
}
|
||||
|
||||
atomic_add(&lock, -1);
|
||||
return sDefaultRoster;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <TranslatorRoster.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
struct translator_data;
|
||||
|
@ -24,11 +25,14 @@ struct translator_data;
|
|||
struct translator_item {
|
||||
BTranslator* translator;
|
||||
entry_ref ref;
|
||||
ino_t node;
|
||||
image_id image;
|
||||
};
|
||||
|
||||
typedef std::map<translator_id, translator_item> TranslatorMap;
|
||||
typedef std::vector<BMessenger> MessengerList;
|
||||
typedef std::vector<node_ref> NodeRefList;
|
||||
typedef std::set<entry_ref> EntryRefSet;
|
||||
|
||||
class BTranslatorRoster::Private : public BHandler, public BLocker {
|
||||
public:
|
||||
|
@ -41,7 +45,9 @@ class BTranslatorRoster::Private : public BHandler, public BLocker {
|
|||
status_t AddPaths(const char* paths);
|
||||
status_t AddPath(const char* path, int32* _added = NULL);
|
||||
status_t AddTranslator(BTranslator* translator, image_id image = -1,
|
||||
const entry_ref* ref = NULL);
|
||||
const entry_ref* ref = NULL, ino_t node = 0);
|
||||
|
||||
void RemoveTranslators(entry_ref& ref);
|
||||
|
||||
BTranslator* FindTranslator(translator_id id);
|
||||
|
||||
|
@ -58,7 +64,8 @@ class BTranslatorRoster::Private : public BHandler, public BLocker {
|
|||
|
||||
bool IsActive() const { return Looper(); }
|
||||
|
||||
status_t CreateTranslators(const entry_ref& ref, int32& count);
|
||||
status_t CreateTranslators(const entry_ref& ref, int32& count,
|
||||
BMessage* update = NULL);
|
||||
status_t GetTranslatorData(image_id image, translator_data& data);
|
||||
|
||||
status_t StartWatching(BMessenger target);
|
||||
|
@ -69,14 +76,31 @@ class BTranslatorRoster::Private : public BHandler, public BLocker {
|
|||
private:
|
||||
static int _CompareSupport(const void* _a, const void* _b);
|
||||
|
||||
void _RescanChanged();
|
||||
|
||||
const translation_format* _CheckHints(const translation_format* formats,
|
||||
int32 formatsCount, uint32 hintType, const char* hintMIME);
|
||||
|
||||
const translator_item* _FindTranslator(translator_id id) const;
|
||||
const translator_item* _FindTranslator(const char* name) const;
|
||||
const translator_item* _FindTranslator(entry_ref& ref) const;
|
||||
translator_item* _FindTranslator(node_ref& nodeRef);
|
||||
|
||||
int32 _CompareTranslatorDirectoryPriority(const entry_ref& a,
|
||||
const entry_ref& b) const;
|
||||
bool _IsKnownDirectory(const node_ref& nodeRef) const;
|
||||
|
||||
void _RemoveTranslators(const node_ref* nodeRef, const entry_ref* ref = NULL);
|
||||
void _EntryAdded(const node_ref& nodeRef, const char* name);
|
||||
void _EntryAdded(const entry_ref& ref);
|
||||
void _NotifyListeners(BMessage& update) const;
|
||||
|
||||
NodeRefList fDirectories;
|
||||
TranslatorMap fTranslators;
|
||||
MessengerList fMessengers;
|
||||
EntryRefSet fRescanEntries;
|
||||
int32 fNextID;
|
||||
bool fLazyScanning;
|
||||
};
|
||||
|
||||
#endif // TRANSLATOR_ROSTER_PRIVATE_H
|
||||
|
|
Loading…
Reference in New Issue