mirror of
https://github.com/darlinghq/darling-dbuskit.git
synced 2024-11-23 12:19:40 +00:00
* Source/DKArgument.[mh]: Implement marshalling of variant types. Also add the
ability to customize the unboxing of objects. * Source/DKEndpoint.m Source/DKMethod.m Source/DKPort.m: Compile fixes for clang. * Source/DKOutgoingProxy.[mh] Source/GNUmakefile: Add stub implementation for outgoing proxies. * Source/DKProxy.m: Add method to distinguish outgoing and incoming proxies. * Source/Tests/TestDKProxy.m: Fix runtime.h include. * Source/Tests/TestDKArgument.m: Add test for custom unboxing methods. * Source/config.h.in config.make.in configure.ac GNUmakefile.postamble: Update configure script and paraphernalia to check for advanced runtime features. * configure: Regenerate Finish implementation of (un-)marshalling values between NSInvocation and D-Bus messages. More flexible scheme for unboxing values. Various smaller fixes. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/dbuskit/trunk@30844 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
00783650d9
commit
c3bc3287dd
@ -29,13 +29,14 @@ after-clean::
|
||||
@-$(RM) -rf DBusKit.framework
|
||||
@-$(RM) -rf derived_src
|
||||
@-$(RM) config.make
|
||||
@-$(RM) Source/config.h
|
||||
|
||||
# Things to do before distcleaning
|
||||
# before-distclean::
|
||||
|
||||
# Things to do after distcleaning
|
||||
after-distclean::
|
||||
@-$(RM) config.log config.status config.make
|
||||
@-$(RM) config.log config.status config.make Source/config.h
|
||||
@-$(RM) -rf autom4te.cache
|
||||
|
||||
# Things to do before checking
|
||||
@ -47,5 +48,5 @@ after-distclean::
|
||||
|
||||
# Rule to generate configuration data:
|
||||
|
||||
config.make: config.make.in
|
||||
config.make: config.make.in Source/config.h.in
|
||||
./configure
|
||||
|
@ -41,6 +41,14 @@ extern NSString *DKArgumentDirectionOut;
|
||||
Class objCEquivalent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the selector to be used for unboxing objects to specific
|
||||
* D-Bus types. The method named by the selector may not take any arguments and
|
||||
* its return value can not exceed 8 bytes.
|
||||
*/
|
||||
+ (void)registerUnboxingSelector: (SEL)selector
|
||||
forDBusType: (int)type;
|
||||
|
||||
- (id) initWithDBusSignature: (const char*)characters
|
||||
name: (NSString*)name
|
||||
parent: (id)parent;
|
||||
@ -67,6 +75,11 @@ extern NSString *DKArgumentDirectionOut;
|
||||
*/
|
||||
- (Class) objCEquivalent;
|
||||
|
||||
/**
|
||||
* Returns the D-Bus type of the argument.
|
||||
*/
|
||||
- (int) DBusType;
|
||||
|
||||
/**
|
||||
* Return the D-Bus type signature equivalent to the argument.
|
||||
*/
|
||||
|
@ -27,14 +27,19 @@
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSHashTable.h>
|
||||
#import <Foundation/NSInvocation.h>
|
||||
#import <Foundation/NSLock.h>
|
||||
#import <Foundation/NSMapTable.h>
|
||||
#import <Foundation/NSMethodSignature.h>
|
||||
#import <Foundation/NSNull.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
#import <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
|
||||
#import "DBusKit/DKProxy.h"
|
||||
#import "DKEndpoint.h"
|
||||
#import "DKOutgoingProxy.h"
|
||||
#import "DKArgument.h"
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
@ -82,13 +87,62 @@ DKObjCClassForDBusType(int type)
|
||||
return Nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* Conversion from Objective-C types to D-Bus types. NOTE: This is not meant to
|
||||
* be complete. It is just used to give some hints for the boxing of D-Bus
|
||||
* variant types. (NSValue responds to -objCType, so we can use the information
|
||||
* to construct a correctly typed DKArgument at least some of the time.)
|
||||
*/
|
||||
static int
|
||||
DKDBusTypeForObjCType(const char* code)
|
||||
{
|
||||
switch (*code)
|
||||
{
|
||||
case _C_BOOL:
|
||||
return DBUS_TYPE_BOOLEAN;
|
||||
case _C_CHR:
|
||||
case _C_SHT:
|
||||
return DBUS_TYPE_INT16;
|
||||
case _C_INT:
|
||||
return DBUS_TYPE_INT32;
|
||||
case _C_LNG_LNG:
|
||||
return DBUS_TYPE_INT64;
|
||||
case _C_UCHR:
|
||||
return DBUS_TYPE_BYTE;
|
||||
case _C_USHT:
|
||||
return DBUS_TYPE_UINT16;
|
||||
case _C_UINT:
|
||||
return DBUS_TYPE_UINT32;
|
||||
case _C_ULNG_LNG:
|
||||
return DBUS_TYPE_UINT64;
|
||||
case _C_FLT:
|
||||
case _C_DBL:
|
||||
return DBUS_TYPE_DOUBLE;
|
||||
case _C_CHARPTR:
|
||||
return DBUS_TYPE_STRING;
|
||||
case _C_ID:
|
||||
return DBUS_TYPE_OBJECT_PATH;
|
||||
case _C_ARY_B:
|
||||
return DBUS_TYPE_ARRAY;
|
||||
case _C_STRUCT_B:
|
||||
return DBUS_TYPE_STRUCT;
|
||||
default:
|
||||
return DBUS_TYPE_INVALID;
|
||||
}
|
||||
return DBUS_TYPE_INVALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map D-Bus types to corresponding Objective-C types. Assumes that complex
|
||||
* types are always boxed.
|
||||
*/
|
||||
static char*
|
||||
DKUnboxedObjCTypeForDBusType(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DBUS_TYPE_BYTE:
|
||||
return @encode(char);
|
||||
return @encode(unsigned char);
|
||||
case DBUS_TYPE_BOOLEAN:
|
||||
return @encode(BOOL);
|
||||
case DBUS_TYPE_INT16:
|
||||
@ -170,6 +224,7 @@ DKUnboxedObjCTypeSizeForDBusType(int type)
|
||||
- (NSString*)_path;
|
||||
- (NSString*)_service;
|
||||
- (DKEndpoint*)_endpoint;
|
||||
- (BOOL)_isLocal;
|
||||
@end
|
||||
|
||||
|
||||
@ -190,6 +245,7 @@ DKUnboxedObjCTypeSizeForDBusType(int type)
|
||||
@end
|
||||
|
||||
@interface DKVariantTypeArgument: DKContainerTypeArgument
|
||||
- (DKArgument*) DKArgumentWithObject: (id)object;
|
||||
@end
|
||||
|
||||
/* It seems sensible to regard dict entries as struct types. */
|
||||
@ -204,10 +260,206 @@ DKUnboxedObjCTypeSizeForDBusType(int type)
|
||||
intoIterator: (DBusMessageIter*)iter;
|
||||
@end
|
||||
|
||||
|
||||
/*
|
||||
* Tables and paraphernalia for managing unboxing of objects: We want some
|
||||
* degree of flexibility on how to unbox objects of arbitrary types. To that
|
||||
* end, we define two tables:
|
||||
*
|
||||
* (1) selectorTypeMap, which maps selectors used to unbox objects to D-Bus
|
||||
* types so that we can construct appropriate DKArguments if we encounter
|
||||
* objects responding to the selector.
|
||||
*
|
||||
* (2) typeSelectorMap, which maps D-Bus types to hash-tables containing all
|
||||
* selectors that can be used to obtain an unboxed value of a specified
|
||||
* type.
|
||||
*
|
||||
* NOTE: Unfortunately, we cannot unbox container types this way.
|
||||
*/
|
||||
static NSMapTable *selectorTypeMap;
|
||||
static NSMapTable *typeSelectorMap;
|
||||
static NSLock *selectorTypeMapLock;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SEL selector;
|
||||
int type;
|
||||
} DKSelectorTypePair;
|
||||
|
||||
|
||||
#define DK_INSTALL_TYPE_SELECTOR_PAIR(type,theSel) \
|
||||
do \
|
||||
{\
|
||||
SEL selector = theSel;\
|
||||
NSHashTable *selTable = NSCreateHashTable(NSIntHashCallBacks,\
|
||||
1); \
|
||||
NSMapInsert(selectorTypeMap,\
|
||||
(void*)(uintptr_t)selector,\
|
||||
(void*)(intptr_t)type);\
|
||||
NSMapInsert(typeSelectorMap,\
|
||||
(void*)(intptr_t)type,\
|
||||
(void*)selTable);\
|
||||
NSHashInsert(selTable,selector);\
|
||||
} while (0)
|
||||
|
||||
|
||||
static void
|
||||
DKInstallDefaultSelectorTypeMapping()
|
||||
{
|
||||
[selectorTypeMapLock lock];
|
||||
DK_INSTALL_TYPE_SELECTOR_PAIR(DBUS_TYPE_INT64, @selector(longLongValue));
|
||||
DK_INSTALL_TYPE_SELECTOR_PAIR(DBUS_TYPE_UINT64, @selector(unsignedLongLongValue));
|
||||
DK_INSTALL_TYPE_SELECTOR_PAIR(DBUS_TYPE_INT32, @selector(intValue));
|
||||
DK_INSTALL_TYPE_SELECTOR_PAIR(DBUS_TYPE_UINT32, @selector(unsignedIntValue));
|
||||
DK_INSTALL_TYPE_SELECTOR_PAIR(DBUS_TYPE_INT16, @selector(shortValue));
|
||||
DK_INSTALL_TYPE_SELECTOR_PAIR(DBUS_TYPE_UINT16, @selector(unsignedShortValue));
|
||||
DK_INSTALL_TYPE_SELECTOR_PAIR(DBUS_TYPE_BYTE, @selector(unsignedCharValue));
|
||||
DK_INSTALL_TYPE_SELECTOR_PAIR(DBUS_TYPE_BOOLEAN, @selector(boolValue));
|
||||
DK_INSTALL_TYPE_SELECTOR_PAIR(DBUS_TYPE_DOUBLE, @selector(doubleValue));
|
||||
DK_INSTALL_TYPE_SELECTOR_PAIR(DBUS_TYPE_DOUBLE, @selector(floatValue));
|
||||
DK_INSTALL_TYPE_SELECTOR_PAIR(DBUS_TYPE_STRING, @selector(UTF8String));
|
||||
[selectorTypeMapLock unlock];
|
||||
}
|
||||
|
||||
static void
|
||||
DKRegisterSelectorTypePair(DKSelectorTypePair *pair)
|
||||
{
|
||||
NSHashTable *selTable = nil;
|
||||
SEL selector = pair->selector;
|
||||
int type = pair->type;
|
||||
void* mapReturn = NULL;
|
||||
if (0 == selector)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
[selectorTypeMapLock lock];
|
||||
selTable = NSMapGet(typeSelectorMap, (void*)(intptr_t)type);
|
||||
|
||||
if (!selTable)
|
||||
{
|
||||
[selectorTypeMapLock unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
mapReturn = NSMapInsertIfAbsent(selectorTypeMap,
|
||||
(void*)(uintptr_t)selector,
|
||||
(void*)(intptr_t)type);
|
||||
|
||||
// InsertIfAbsent returns NULL if the key had been absent, which is the only
|
||||
// case where we also want to install the new type-selector mapping.
|
||||
if (NULL == mapReturn)
|
||||
{
|
||||
NSHashInsertIfAbsent(selTable, (void*)(uintptr_t)selector);
|
||||
}
|
||||
[selectorTypeMapLock unlock];
|
||||
}
|
||||
|
||||
|
||||
static SEL
|
||||
DKSelectorForUnboxingObjectAsType(id object, int DBusType)
|
||||
{
|
||||
SEL theSel = 0;
|
||||
NSHashTable *table = nil;
|
||||
NSHashEnumerator tableEnum;
|
||||
[selectorTypeMapLock lock];
|
||||
table = NSMapGet(typeSelectorMap, (void*)(intptr_t)DBusType);
|
||||
tableEnum = NSEnumerateHashTable(table);
|
||||
while (0 != (theSel = (SEL)NSNextHashEnumeratorItem(&tableEnum)))
|
||||
{
|
||||
if ([object respondsToSelector: theSel])
|
||||
{
|
||||
NSEndHashTableEnumeration(&tableEnum);
|
||||
[selectorTypeMapLock unlock];
|
||||
return theSel;
|
||||
}
|
||||
}
|
||||
NSEndHashTableEnumeration(&tableEnum);
|
||||
[selectorTypeMapLock unlock];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
DKDBusTypeForUnboxingObject(id object)
|
||||
{
|
||||
int type = DBUS_TYPE_INVALID;
|
||||
// Fast case: The object implements objCType, so we can simply gather the
|
||||
// D-Bus type from the Obj-C type code.
|
||||
if ([object respondsToSelector: @selector(objCType)])
|
||||
{
|
||||
type = DKDBusTypeForObjCType([object objCType]);
|
||||
}
|
||||
|
||||
// Slow case: We need to find a selector in the table and get the matching
|
||||
// type.
|
||||
if (DBUS_TYPE_INVALID == type)
|
||||
{
|
||||
SEL aSel = 0;
|
||||
NSMapEnumerator mapEnum;
|
||||
[selectorTypeMapLock lock];
|
||||
mapEnum = NSEnumerateMapTable(selectorTypeMap);
|
||||
while (NSNextMapEnumeratorPair(&mapEnum,
|
||||
(void**)&aSel,
|
||||
(void**)&type))
|
||||
{
|
||||
if (aSel != 0)
|
||||
{
|
||||
if ([object respondsToSelector: aSel])
|
||||
{
|
||||
// The object responds to the selector. We need to make sure that we
|
||||
// get a correctly sized return value by invoking the corresponding
|
||||
// method.
|
||||
NSMethodSignature *sig = [object methodSignatureForSelector: aSel];
|
||||
if ((type == DKDBusTypeForObjCType([sig methodReturnType])))
|
||||
{
|
||||
NSEndMapTableEnumeration(&mapEnum);
|
||||
[selectorTypeMapLock unlock];
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NSEndMapTableEnumeration(&mapEnum);
|
||||
[selectorTypeMapLock unlock];
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* DKArgument encapsulates D-Bus argument information
|
||||
*/
|
||||
@implementation DKArgument
|
||||
+ (void) initialize
|
||||
{
|
||||
if ([DKArgument class] != self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
selectorTypeMap = NSCreateMapTable(NSIntMapKeyCallBacks,
|
||||
NSIntMapValueCallBacks,
|
||||
17); // We have 17 D-Bus types.
|
||||
typeSelectorMap = NSCreateMapTable(NSIntMapKeyCallBacks,
|
||||
NSObjectMapValueCallBacks,
|
||||
17); // We have 17 D-Bus types.
|
||||
|
||||
|
||||
selectorTypeMapLock = [NSLock new];
|
||||
DKInstallDefaultSelectorTypeMapping();
|
||||
|
||||
|
||||
}
|
||||
|
||||
+ (void)registerUnboxingSelector: (SEL)selector
|
||||
forDBusType: (int)type
|
||||
{
|
||||
|
||||
DKSelectorTypePair pair = {selector, type};
|
||||
DKRegisterSelectorTypePair(&pair);
|
||||
}
|
||||
|
||||
- (id) initWithIterator: (DBusSignatureIter*)iterator
|
||||
name: (NSString*)_name
|
||||
parent: (id)_parent
|
||||
@ -316,6 +568,7 @@ DKUnboxedObjCTypeSizeForDBusType(int type)
|
||||
- (BOOL) unboxValue: (id)value
|
||||
intoBuffer: (long long*)buffer
|
||||
{
|
||||
SEL aSelector = 0;
|
||||
switch (DBusType)
|
||||
{
|
||||
case DBUS_TYPE_BYTE:
|
||||
@ -397,16 +650,37 @@ DKUnboxedObjCTypeSizeForDBusType(int type)
|
||||
case DBUS_TYPE_OBJECT_PATH:
|
||||
if ([value isKindOfClass: [DKProxy class]])
|
||||
{
|
||||
DKProxy *rootProxy = [self proxyParent];
|
||||
/*
|
||||
* Handle remote objects:
|
||||
* We need to make sure that the paths are from the same proxy, because
|
||||
* that is the widest scope in which they are valid.
|
||||
*/
|
||||
if ([[self proxyParent] hasSameScopeAs: value])
|
||||
if ([rootProxy hasSameScopeAs: value])
|
||||
{
|
||||
*buffer = (uintptr_t)[[value _path] UTF8String];
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DKProxy *rootProxy = [self proxyParent];
|
||||
/*
|
||||
* Handle local objects:
|
||||
* We need to find out if the proxy we derive from is an outgoing proxy.
|
||||
* If so, we can export the object via D-Bus, so that the caller can
|
||||
* interact with it.
|
||||
*/
|
||||
if ([rootProxy _isLocal])
|
||||
{
|
||||
DKOutgoingProxy *newProxy = [DKOutgoingProxy proxyWithParent: rootProxy
|
||||
object: value];
|
||||
*buffer = (uintptr_t)[[newProxy _path] UTF8String];
|
||||
[newProxy release];
|
||||
return YES;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case DBUS_TYPE_SIGNATURE:
|
||||
if ([value respondsToSelector: @selector(DBusTypeSignature)])
|
||||
@ -418,6 +692,29 @@ DKUnboxedObjCTypeSizeForDBusType(int type)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* None of the built in mappings worked. We still have a slight chance that a
|
||||
* custom selector was installed to unbox the type. So we try again by looking
|
||||
* up the selector.
|
||||
*/
|
||||
aSelector = DKSelectorForUnboxingObjectAsType(value, DBusType);
|
||||
if (0 != aSelector)
|
||||
{
|
||||
NSMethodSignature *sig = [value methodSignatureForSelector: aSelector];
|
||||
// Only call it if we don't need arguments and the returnvalue fits into
|
||||
// the buffer:
|
||||
if ((2 == [sig numberOfArguments])
|
||||
&& ([sig methodReturnLength] <= sizeof(long long)))
|
||||
{
|
||||
IMP unboxFun = [value methodForSelector: aSelector];
|
||||
|
||||
// Cast to void* first so that we don't get any funny implicit casts
|
||||
*buffer = (long long)(void*)unboxFun(value, aSelector);
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@ -662,9 +959,11 @@ DKUnboxedObjCTypeSizeForDBusType(int type)
|
||||
case DBUS_TYPE_VARIANT:
|
||||
/*
|
||||
* A shortcut is needed for variant types. libdbus classifies them as
|
||||
* containers, but it is clearly wrong about that: They have no children
|
||||
* and dbus will fail and crash if it tries to loop over their non-existent
|
||||
* sub-arguments. Hence we return after setting the subclass.
|
||||
* containers, but it is clearly wrong about that at least with regard to
|
||||
* the signatures:
|
||||
* They have no children and dbus will fail and crash if it tries to loop
|
||||
* over their non-existent sub-arguments. Hence we return after setting the
|
||||
* subclass.
|
||||
*/
|
||||
isa = [DKVariantTypeArgument class];
|
||||
return self;
|
||||
@ -814,13 +1113,13 @@ DKUnboxedObjCTypeSizeForDBusType(int type)
|
||||
|
||||
if (-1 == index)
|
||||
{
|
||||
NSAssert((@encode(id) == [[inv methodSignature] methodReturnType]),
|
||||
NSAssert((0 == strcmp(@encode(id), [[inv methodSignature] methodReturnType])),
|
||||
@"Type mismatch between introspection data and invocation.");
|
||||
[inv setReturnValue: &value];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSAssert((@encode(id) == [[inv methodSignature] getArgumentTypeAtIndex: index]),
|
||||
NSAssert((0 == strcmp(@encode(id), [[inv methodSignature] getArgumentTypeAtIndex: index])),
|
||||
@"Type mismatch between introspection data and invocation.");
|
||||
[inv setArgument: &value
|
||||
atIndex: index];
|
||||
@ -842,13 +1141,13 @@ DKUnboxedObjCTypeSizeForDBusType(int type)
|
||||
|
||||
if (-1 == index)
|
||||
{
|
||||
NSAssert((@encode(id) == [[inv methodSignature] methodReturnType]),
|
||||
NSAssert((0 == strcmp(@encode(id), [[inv methodSignature] methodReturnType])),
|
||||
@"Type mismatch between introspection data and invocation.");
|
||||
[inv getReturnValue: &value];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSAssert((@encode(id) == [[inv methodSignature] getArgumentTypeAtIndex: index]),
|
||||
NSAssert((0 == strcmp(@encode(id), [[inv methodSignature] getArgumentTypeAtIndex: index])),
|
||||
@"Type mismatch between introspection data and invocation.");
|
||||
[inv getArgument: &value
|
||||
atIndex: index];
|
||||
@ -1214,7 +1513,105 @@ DKUnboxedObjCTypeSizeForDBusType(int type)
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation DKVariantTypeArgument
|
||||
|
||||
- (NSString*)validSubSignatureOrVariantForEnumerator: (NSEnumerator*)theEnum
|
||||
{
|
||||
id element = [theEnum nextObject];
|
||||
NSString *thisSig = [[self DKArgumentWithObject: element] DBusTypeSignature];
|
||||
NSString *nextSig = thisSig;
|
||||
|
||||
// For homogenous collection, we can the proper signature, for non-homogenous
|
||||
// ones, we need to pass down the variant type.
|
||||
BOOL isHomogenous = YES;
|
||||
while ((nil != (element = [theEnum nextObject]))
|
||||
&& (YES == isHomogenous))
|
||||
{
|
||||
thisSig = nextSig;
|
||||
nextSig = [[self DKArgumentWithObject: element] DBusTypeSignature];
|
||||
isHomogenous = [thisSig isEqualToString: nextSig];
|
||||
}
|
||||
|
||||
if (isHomogenous)
|
||||
{
|
||||
return thisSig;
|
||||
}
|
||||
else
|
||||
{
|
||||
return @"v";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (DKArgument*) DKArgumentWithObject: (id)object
|
||||
{
|
||||
if (([object respondsToSelector: @selector(keyEnumerator)])
|
||||
&& ([object respondsToSelector: @selector(objectEnumerator)]))
|
||||
{
|
||||
NSEnumerator *keyEnum = [object keyEnumerator];
|
||||
NSEnumerator *objEnum = [object objectEnumerator];
|
||||
NSString *keySig = [self validSubSignatureOrVariantForEnumerator: keyEnum];
|
||||
NSString *objSig = [self validSubSignatureOrVariantForEnumerator: objEnum];
|
||||
NSString *theSig = [NSString stringWithFormat: @"a{%@%@}", keySig, objSig];
|
||||
DKArgument *subArg = [[[DKArgument alloc] initWithDBusSignature: [theSig UTF8String]
|
||||
name: nil
|
||||
parent: self] autorelease];
|
||||
if (nil == subArg)
|
||||
{
|
||||
// This might happen if the dictionary could not properly be represented as
|
||||
// a D-Bus dictionary (i.e. it has keys of complex type. In this case, we
|
||||
// fall back to representing it as an array of structs:
|
||||
theSig = [NSString stringWithFormat: @"a(%@%@)", keySig, objSig];
|
||||
subArg = [[[DKArgument alloc] initWithDBusSignature: [theSig UTF8String]
|
||||
name: nil
|
||||
parent: self] autorelease];
|
||||
}
|
||||
return subArg;
|
||||
}
|
||||
else if ([object respondsToSelector: @selector(objectEnumerator)])
|
||||
{
|
||||
NSEnumerator *theEnum = [object objectEnumerator];
|
||||
NSString *subSig = [self validSubSignatureOrVariantForEnumerator: theEnum];
|
||||
return [[[DKArgument alloc] initWithDBusSignature: [[@"a" stringByAppendingString: subSig] UTF8String]
|
||||
name: nil
|
||||
parent: self] autorelease];
|
||||
}
|
||||
else if ([object isKindOfClass: [DKProxy class]])
|
||||
{
|
||||
DKProxy *rootProxy = [self proxyParent];
|
||||
if ([rootProxy hasSameScopeAs: object])
|
||||
{
|
||||
return [[[DKArgument alloc] initWithDBusSignature: DBUS_TYPE_OBJECT_PATH_AS_STRING
|
||||
name: nil
|
||||
parent: self] autorelease];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Simple types are quite straightforward, if we can find an appropriate
|
||||
// deserialization selector.
|
||||
int type = DKDBusTypeForUnboxingObject(object);
|
||||
if ((DBUS_TYPE_INVALID != type) && (DBUS_TYPE_OBJECT_PATH != type))
|
||||
{
|
||||
return [[DKArgument alloc] initWithDBusSignature: (char*)&type
|
||||
name: nil
|
||||
parent: self];
|
||||
}
|
||||
else if ([[self proxyParent] _isLocal])
|
||||
{
|
||||
// If this fails, and the proxy from which this argument derives is an
|
||||
// outgoing proxy, we can export it as an object path.
|
||||
return [[[DKArgument alloc] initWithDBusSignature: DBUS_TYPE_OBJECT_PATH_AS_STRING
|
||||
name: nil
|
||||
parent: self] autorelease];
|
||||
}
|
||||
}
|
||||
// Too bad, we have apparantely no chance to generate an argument tree for
|
||||
// this object.
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id) unmarshalledObjectFromIterator: (DBusMessageIter*)iter
|
||||
{
|
||||
char *theSig = NULL;
|
||||
@ -1238,7 +1635,33 @@ DKUnboxedObjCTypeSizeForDBusType(int type)
|
||||
- (void) marshallObject: (id)object
|
||||
intoIterator: (DBusMessageIter*)iter
|
||||
{
|
||||
//FIXME: Implement
|
||||
DKArgument *subArg = [self DKArgumentWithObject: object];
|
||||
DBusMessageIter subIter;
|
||||
|
||||
NSAssert1(subArg,
|
||||
@"Could not marshall object %@ as D-Bus variant type",
|
||||
subArg);
|
||||
|
||||
NSAssert(dbus_message_iter_open_container(iter,
|
||||
DBUS_TYPE_ARRAY,
|
||||
[[subArg DBusTypeSignature] UTF8String],
|
||||
&subIter),
|
||||
@"Out of memory when creating D-Bus iterator for container.");
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
[subArg marshallObject: object
|
||||
intoIterator: &subIter];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
dbus_message_iter_close_container(iter, &subIter);
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
|
||||
NSAssert(dbus_message_iter_close_container(iter, &subIter),
|
||||
@"Out of memory when closing D-Bus container.");
|
||||
}
|
||||
@end
|
||||
|
||||
|
@ -327,14 +327,12 @@ static NSRecursiveLock *activeConnectionLock;
|
||||
|
||||
- (id) initWithCoder: (NSCoder*)coder
|
||||
{
|
||||
if ([super respondsToSelector: @selector(initWithCoder:)])
|
||||
// NSObject does not adopt NSCoding
|
||||
if (nil == (self = [super init]))
|
||||
{
|
||||
self = [(id<NSCoding>)super initWithCoder: coder];
|
||||
}
|
||||
else
|
||||
{
|
||||
self = [super init];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ([coder allowsKeyedCoding])
|
||||
{
|
||||
info = [coder decodeObjectForKey: @"DKEndpointInfo"];
|
||||
@ -448,10 +446,7 @@ static NSRecursiveLock *activeConnectionLock;
|
||||
format: @"This DKEndpoint has been create with a private initializer and cannot be encoded."];
|
||||
}
|
||||
|
||||
if ([super respondsToSelector: @selector(encodeWithCoder:)])
|
||||
{
|
||||
[(id<NSCoding>)super encodeWithCoder: coder];
|
||||
}
|
||||
// NSObject doesn't adopt NSCoding, so we don't do [super encodeWithCoder:].
|
||||
|
||||
if ([coder allowsKeyedCoding])
|
||||
{
|
||||
|
@ -288,7 +288,7 @@ DKMethod *_DKMethodIntrospect;
|
||||
NSMethodSignature *sig = [inv methodSignature];
|
||||
|
||||
// Make sure the method did return an object:
|
||||
NSAssert2((@encode(id) == [sig methodReturnType]),
|
||||
NSAssert2((0 == strcmp(@encode(id), [sig methodReturnType])),
|
||||
@"Invalid return value when constucting D-Bus reply for '%@' on %@",
|
||||
NSStringFromSelector([inv selector]),
|
||||
[inv target]);
|
||||
|
33
Source/DKOutgoingProxy.h
Normal file
33
Source/DKOutgoingProxy.h
Normal file
@ -0,0 +1,33 @@
|
||||
/** Interface for the DKOutgoingProxy class for exporting objects via D-Bus
|
||||
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Niels Grewe <niels.grewe@halbordnung.de>
|
||||
Created: June 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#include "DBusKit/DKProxy.h"
|
||||
|
||||
@interface DKOutgoingProxy: DKProxy
|
||||
/**
|
||||
* Exports anObject via D-Bus by installing it in the object graph as a child of
|
||||
* rootProxy.
|
||||
*/
|
||||
+ (id) proxyWithParent: (DKProxy*)rootProxy
|
||||
object: (id)anObject;
|
||||
@end
|
37
Source/DKOutgoingProxy.m
Normal file
37
Source/DKOutgoingProxy.m
Normal file
@ -0,0 +1,37 @@
|
||||
/** Implementation of the DKOutgoingProxy class for exporting objects via D-Bus
|
||||
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Niels Grewe <niels.grewe@halbordnung.de>
|
||||
Created: June 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#include "DKOutgoingProxy.h"
|
||||
|
||||
@implementation DKOutgoingProxy
|
||||
+ (id) proxyWithParent: (DKProxy*)rootProxy
|
||||
object: (id)anObject
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)_isLocal
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
@end
|
@ -122,7 +122,7 @@ enum {
|
||||
* This is the main method used to dispatch stuff from the DO system to D-Bus.
|
||||
*/
|
||||
- (BOOL)sendBeforeDate: (NSDate *)limitDate
|
||||
msgid: (NSUInteger)msgid
|
||||
msgid: (NSInteger)msgid
|
||||
components: (NSMutableArray *)components
|
||||
from: (NSPort *)recievePort
|
||||
reserved: (NSUInteger)reserverdHeaderSpace
|
||||
@ -215,7 +215,7 @@ enum {
|
||||
extra: (void*)extra
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
NSLog(@"RunLoop events: Ignoring event of type %ld", type);
|
||||
NSLog(@"RunLoop events: Ignoring event of type %llu", (unsigned long long)type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -320,6 +320,11 @@
|
||||
return path;
|
||||
}
|
||||
|
||||
- (BOOL)_isLocal
|
||||
{
|
||||
// True only for outgoing proxies representing local objects.
|
||||
return NO;
|
||||
}
|
||||
- (BOOL) hasSameScopeAs: (DKProxy*)aProxy
|
||||
{
|
||||
BOOL sameService = [service isEqualToString: [aProxy _service]];
|
||||
|
@ -18,6 +18,7 @@ libDBusKit_OBJC_FILES = \
|
||||
DKInterface.m \
|
||||
DKIntrospectionNode.m \
|
||||
DKMethod.m \
|
||||
DKOutgoingProxy.m \
|
||||
DKPort.m \
|
||||
DKProxy.m
|
||||
|
||||
|
@ -35,6 +35,32 @@
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
|
||||
@interface CustomUnboxableObject: NSObject
|
||||
{
|
||||
int32_t foo;
|
||||
}
|
||||
- (int32_t)myInt32Value;
|
||||
@end
|
||||
|
||||
@implementation CustomUnboxableObject
|
||||
- (id) init
|
||||
{
|
||||
if (nil == (self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
foo = 42;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (int32_t)myInt32Value
|
||||
{
|
||||
return foo;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface TestDKArgument: NSObject <UKTest>
|
||||
@end
|
||||
|
||||
@ -449,4 +475,19 @@ static NSDictionary *basicSigsAndClasses;
|
||||
|
||||
[arg release];
|
||||
}
|
||||
|
||||
- (void)testCustomUnboxingSelector
|
||||
{
|
||||
|
||||
DKArgument *arg = [[DKArgument alloc] initWithDBusSignature: "i"
|
||||
name: nil
|
||||
parent: nil];
|
||||
id boxedFoo = [[CustomUnboxableObject alloc] init];
|
||||
int32_t foo = [boxedFoo myInt32Value];
|
||||
[DKArgument registerUnboxingSelector: @selector(myInt32Value)
|
||||
forDBusType: DBUS_TYPE_INT32];
|
||||
TEST_UNBOX_INTTYPE(int32_t);
|
||||
[boxedFoo release];
|
||||
[arg release];
|
||||
}
|
||||
@end
|
||||
|
@ -22,7 +22,9 @@
|
||||
*/
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <UnitKit/UnitKit.h>
|
||||
#import <objc/runtime.h>
|
||||
#define INCLUDE_RUNTIME_H
|
||||
#include "../config.h"
|
||||
#undef INCLUDE_RUNTIME_H
|
||||
|
||||
#import "../../Headers/DKProxy.h"
|
||||
#import "../DKEndpoint.h"
|
||||
|
47
Source/config.h.in
Normal file
47
Source/config.h.in
Normal file
@ -0,0 +1,47 @@
|
||||
/** Configuration dependent information for DBusKit.
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Niels Grewe <niels.grewe@halbordnung.de>
|
||||
Created: June 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Having libtoydispatch enables some asynchronous behaviour.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_TOYDISPATCH
|
||||
# define HAVE_TOYDISPATCH @HAVE_TOYDISPATCH@
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Typed selectors enable automatic distinction between boxed and unboxed
|
||||
* variants of D-Bus method calls.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_TYPED_SELECTORS
|
||||
# define HAVE_TYPED_SELECTORS @HAVE_TYPED_SELECTORS@
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Correct location of runtime.h, if requested.
|
||||
*/
|
||||
|
||||
#ifdef INCLUDE_RUNTIME_H
|
||||
# include <@OBJC_RUNTIME_H@>
|
||||
#endif
|
@ -1,3 +1,6 @@
|
||||
ifeq ($(strip $(CC)),)
|
||||
CC=@CC@
|
||||
endif
|
||||
ADDITIONAL_OBJCFLAGS+=@DBUS_CFLAGS@
|
||||
WARN_FLAGS+=@WARN_FLAGS@
|
||||
DBusKit_LDFLAGS+=@DBUS_LIBS@
|
||||
DBusKit_LDFLAGS+=@DBUS_LIBS@ @MORE_LIBS@
|
||||
|
69
configure.ac
69
configure.ac
@ -1,7 +1,9 @@
|
||||
# autoconf template for the configure script
|
||||
|
||||
AC_INIT
|
||||
|
||||
AC_PROG_CC(clang gcc cc c1 egcs)
|
||||
AC_PROG_CPP
|
||||
AC_LANG(Objective C)
|
||||
PKG_PROG_PKG_CONFIG([])
|
||||
|
||||
# FIXME: We need a proper test for libobjc2 for some advanced features (e.g.
|
||||
@ -43,6 +45,69 @@ fi
|
||||
|
||||
AC_SUBST(WARN_FLAGS)
|
||||
|
||||
AC_CONFIG_FILES([config.make])
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Check whether we have libtoydispatch for asynchronous table management.
|
||||
#--------------------------------------------------------------------
|
||||
HAVE_TOYDISPATCH=0
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
saved_CPPFLAGS="$CPPFLAGS$"
|
||||
saved_LDFLAGS="$LDFLAGS"
|
||||
GS_OBJCFLAGS=`gnustep-config --objc-flags`
|
||||
CFLAGS="$CFLAGS $GS_OBJCFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $GS_OBJCFLAGS"
|
||||
GS_LDFLAGS=`gnustep-config --objc-libs`
|
||||
LDFLAGS="$LDFLAGS $GS_LDFLAGS"
|
||||
|
||||
AC_CHECK_HEADERS(toydispatch/toydispatch.h,have_toydispatch=yes,have_toydispatch=no)
|
||||
if test "$have_toydispatch" = "yes"; then
|
||||
AC_CHECK_LIB(toydispatch, toy_dispatch_queue_create, have_toydispatch=yes, have_toydispatch=no)
|
||||
if test "$have_toydispatch" = "yes"; then
|
||||
HAVE_TOYDISPATCH=1
|
||||
MORE_LIBS="$MORE_LIBS -ltoydispatch"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(HAVE_TOYDISPATCH)
|
||||
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Check whether we can use typed selectors
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
HAVE_TYPED_SELECTORS=0
|
||||
AC_CHECK_LIB(objc, sel_registerTypedName_np, have_typed_selectors=yes, have_typed_selectors=no)
|
||||
if test "$have_typed_selectors" = "yes"; then
|
||||
HAVE_TYPED_SELECTORS=1
|
||||
fi
|
||||
|
||||
AC_SUBST(HAVE_TYPED_SELECTORS)
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Check whether we get runtime.h from libobjc2 or from the ObjectiveC2
|
||||
# framework
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
|
||||
AC_CHECK_HEADERS(objc/runtime.h,have_libobjc2_runtime_h=yes,have_libobjc2_runtime_h=no)
|
||||
if test "$have_libobjc2_runtime_h" = "yes"; then
|
||||
OBJC_RUNTIME_H="objc/runtime.h"
|
||||
else
|
||||
AC_CHECK_HEADERS(ObjectiveC2/runtime.h,have_objectivec2_runtime_h=yes,have_objectivec2_runtime_h=no)
|
||||
if test "$have_objectivec2_runtime_h" = "yes"; then
|
||||
OBJC_RUNTIME_H="ObjectiveC2/runtime.h"
|
||||
else
|
||||
AC_MSG_ERROR("could not find runtime.h. DBusKit requires gnustep-base >=1.20.")
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(OBJC_RUNTIME_H)
|
||||
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
CPPFLAGS="$saved_CPPFLAGS"
|
||||
LDFLAGS="$saved_LDFLAGS"
|
||||
|
||||
AC_SUBST(MORE_LIBS)
|
||||
AC_CONFIG_FILES([config.make Source/config.h])
|
||||
|
||||
AC_OUTPUT
|
||||
|
Loading…
Reference in New Issue
Block a user