1 /++ 2 A module mostly copied from https://github.com/trishume/ddbus to help access the C dbus library on Linux. 3 +/ 4 module arsd.dbus; 5 6 pragma(lib, "dbus-1"); 7 8 import core.time : Duration; 9 import std.meta; 10 import std.string; 11 import std.typecons; 12 import std.exception; 13 import std.traits; 14 import std.conv; 15 import std.range; 16 import std.algorithm; 17 18 import core.memory; 19 import std.array; 20 import std.format; 21 22 import std.meta : AliasSeq, staticIndexOf; 23 import std.range; 24 import std.traits; 25 import std.variant : VariantN; 26 27 28 /++ 29 Flags for use with dbusMarshaling UDA 30 31 Default is to include public fields only 32 +/ 33 enum MarshalingFlag : ubyte { 34 includePrivateFields = 1 << 0, /// Automatically include private fields 35 manualOnly = 1 << 7 /// Only include fields with explicit 36 /// `@Yes.DBusMarshal`. This overrides any 37 /// `include` flags. 38 } 39 40 /++ 41 UDA for specifying DBus marshaling options on structs 42 +/ 43 auto dbusMarshaling(Args)(Args args ...) 44 if (allSatisfy!(isMarshalingFlag, Args)) { 45 return BitFlags!MarshalingFlag(args); 46 } 47 48 private template isAllowedField(alias field) { 49 private enum flags = marshalingFlags!(__traits(parent, field)); 50 private alias getUDAs!(field, Flag!"DBusMarshal") UDAs; 51 52 static if (UDAs.length != 0) { 53 static assert (UDAs.length == 1, 54 "Only one UDA of type Flag!\"DBusMarshal\" allowed on struct field."); 55 static assert (is(typeof(UDAs[0]) == Flag!"DBusMarshal"), 56 "Did you intend to add UDA Yes.DBusMarshal or No.DBusMarshal?"); 57 enum isAllowedField = cast(bool) UDAs[0]; 58 } else static if (!(flags & MarshalingFlag.manualOnly)) { 59 static if (__traits(getProtection, field) == "public") 60 enum isAllowedField = true; 61 else static if (cast(bool) (flags & MarshalingFlag.includePrivateFields)) 62 enum isAllowedField = true; 63 else 64 enum isAllowedField = false; 65 } else 66 enum isAllowedField = false; 67 } 68 69 private template isMarshalingFlag(T) { 70 enum isMarshalingFlag = is(T == MarshalingFlag); 71 } 72 73 private template marshalingFlags(S) if (is(S == struct)) { 74 private alias getUDAs!(S, BitFlags!MarshalingFlag) UDAs; 75 76 static if (UDAs.length == 0) 77 enum marshalingFlags = BitFlags!MarshalingFlag.init; 78 else { 79 static assert (UDAs.length == 1, 80 "Only one @dbusMarshaling UDA allowed on type."); 81 static assert (is(typeof(UDAs[0]) == BitFlags!MarshalingFlag), 82 "Huh? Did you intend to use @dbusMarshaling UDA?"); 83 enum marshalingFlags = UDAs[0]; 84 } 85 } 86 87 struct DictionaryEntry(K, V) { 88 K key; 89 V value; 90 } 91 92 auto byDictionaryEntries(K, V)(V[K] aa) { 93 return aa.byKeyValue.map!(pair => DictionaryEntry!(K, V)(pair.key, pair.value)); 94 } 95 96 template VariantType(T) { 97 alias VariantType = TemplateArgsOf!(T)[0]; 98 } 99 100 template allCanDBus(TS...) { 101 static if (TS.length == 0) { 102 enum allCanDBus = true; 103 } else static if(!canDBus!(TS[0])) { 104 enum allCanDBus = false; 105 } else { 106 enum allCanDBus = allCanDBus!(TS[1..$]); 107 } 108 } 109 110 /++ 111 AliasSeq of all basic types in terms of the DBus typesystem 112 +/ 113 private // Don't add to the API yet, 'cause I intend to move it later 114 alias BasicTypes = AliasSeq!( 115 bool, 116 byte, 117 short, 118 ushort, 119 int, 120 uint, 121 long, 122 ulong, 123 double, 124 string, 125 ObjectPath 126 ); 127 128 template basicDBus(T) { 129 static if(staticIndexOf!(T, BasicTypes) >= 0) { 130 enum basicDBus = true; 131 } else static if(is(T B == enum)) { 132 enum basicDBus = basicDBus!B; 133 } else static if(isInstanceOf!(BitFlags, T)) { 134 alias TemplateArgsOf!T[0] E; 135 enum basicDBus = basicDBus!E; 136 } else { 137 enum basicDBus = false; 138 } 139 } 140 141 template canDBus(T) { 142 static if(basicDBus!T || is(T == DBusAny)) { 143 enum canDBus = true; 144 } else static if(isInstanceOf!(Variant, T)) { 145 enum canDBus = canDBus!(VariantType!T); 146 } else static if(isInstanceOf!(VariantN, T)) { 147 // Phobos-style variants are supported if limited to DBus compatible types. 148 enum canDBus = (T.AllowedTypes.length > 0) && allCanDBus!(T.AllowedTypes); 149 } else static if(isTuple!T) { 150 enum canDBus = allCanDBus!(T.Types); 151 } else static if(isInputRange!T) { 152 static if(is(ElementType!T == DictionaryEntry!(K, V), K, V)) { 153 enum canDBus = basicDBus!K && canDBus!V; 154 } else { 155 enum canDBus = canDBus!(ElementType!T); 156 } 157 } else static if(isAssociativeArray!T) { 158 enum canDBus = basicDBus!(KeyType!T) && canDBus!(ValueType!T); 159 } else static if(is(T == struct) && !isInstanceOf!(DictionaryEntry, T)) { 160 enum canDBus = allCanDBus!(AllowedFieldTypes!T); 161 } else { 162 enum canDBus = false; 163 } 164 } 165 166 string typeSig(T)() if(canDBus!T) { 167 static if(is(T == byte)) { 168 return "y"; 169 } else static if(is(T == bool)) { 170 return "b"; 171 } else static if(is(T == short)) { 172 return "n"; 173 } else static if(is(T == ushort)) { 174 return "q"; 175 } else static if(is(T == int)) { 176 return "i"; 177 } else static if(is(T == uint)) { 178 return "u"; 179 } else static if(is(T == long)) { 180 return "x"; 181 } else static if(is(T == ulong)) { 182 return "t"; 183 } else static if(is(T == double)) { 184 return "d"; 185 } else static if(is(T == string)) { 186 return "s"; 187 } else static if(is(T == ObjectPath)) { 188 return "o"; 189 } else static if(isInstanceOf!(Variant, T) || isInstanceOf!(VariantN, T)) { 190 return "v"; 191 } else static if(is(T B == enum)) { 192 return typeSig!B; 193 } else static if(isInstanceOf!(BitFlags, T)) { 194 alias TemplateArgsOf!T[0] E; 195 return typeSig!E; 196 } else static if(is(T == DBusAny)) { 197 static assert(false, "Cannot determine type signature of DBusAny. Change to Variant!DBusAny if a variant was desired."); 198 } else static if(isTuple!T) { 199 string sig = "("; 200 foreach(i, S; T.Types) { 201 sig ~= typeSig!S(); 202 } 203 sig ~= ")"; 204 return sig; 205 } else static if(isInputRange!T) { 206 return "a" ~ typeSig!(ElementType!T)(); 207 } else static if(isAssociativeArray!T) { 208 return "a{" ~ typeSig!(KeyType!T) ~ typeSig!(ValueType!T) ~ "}"; 209 } else static if(is(T == struct)) { 210 string sig = "("; 211 foreach(i, S; AllowedFieldTypes!T) { 212 sig ~= typeSig!S(); 213 } 214 sig ~= ")"; 215 return sig; 216 } 217 } 218 219 string typeSig(T)() if(isInstanceOf!(DictionaryEntry, T)) { 220 alias typeof(T.key) K; 221 alias typeof(T.value) V; 222 return "{" ~ typeSig!K ~ typeSig!V ~ '}'; 223 } 224 225 string[] typeSigReturn(T)() if(canDBus!T) { 226 static if(is(T == Tuple!TS, TS...)) 227 return typeSigArr!TS; 228 else 229 return [typeSig!T]; 230 } 231 232 string typeSigAll(TS...)() if(allCanDBus!TS) { 233 string sig = ""; 234 foreach(i,T; TS) { 235 sig ~= typeSig!T(); 236 } 237 return sig; 238 } 239 240 string[] typeSigArr(TS...)() if(allCanDBus!TS) { 241 string[] sig = []; 242 foreach(i,T; TS) { 243 sig ~= typeSig!T(); 244 } 245 return sig; 246 } 247 248 int typeCode(T)() if(canDBus!T) { 249 int code = typeSig!T()[0]; 250 return (code != '(') ? code : 'r'; 251 } 252 253 int typeCode(T)() if(isInstanceOf!(DictionaryEntry, T) && canDBus!(T[])) { 254 return 'e'; 255 } 256 257 private template AllowedFieldTypes(S) if (is(S == struct)) { 258 static alias TypeOf(alias sym) = typeof(sym); 259 260 alias AllowedFieldTypes = 261 staticMap!(TypeOf, Filter!(isAllowedField, S.tupleof)); 262 } 263 264 struct ObjectPath { 265 private string _value; 266 267 this(string objPath) pure @safe { 268 enforce(isValid(objPath)); 269 _value = objPath; 270 } 271 272 string toString() const { 273 return _value; 274 } 275 276 /++ 277 Returns the string representation of this ObjectPath. 278 +/ 279 string value() const pure @nogc nothrow @safe { 280 return _value; 281 } 282 283 size_t toHash() const pure @nogc nothrow @trusted { 284 return hashOf(_value); 285 } 286 287 bool opEquals(ref const typeof(this) b) const pure @nogc nothrow @safe { 288 return _value == b._value; 289 } 290 291 ObjectPath opBinary(string op : "~")(string rhs) const pure @safe { 292 if (!rhs.startsWith("/")) 293 return opBinary!"~"(ObjectPath("/" ~ rhs)); 294 else 295 return opBinary!"~"(ObjectPath(rhs)); 296 } 297 298 ObjectPath opBinary(string op : "~")(ObjectPath rhs) const pure @safe 299 in { 300 assert(ObjectPath.isValid(_value) && ObjectPath.isValid(rhs._value)); 301 } out (v) { 302 assert(ObjectPath.isValid(v._value)); 303 } do { 304 ObjectPath ret; 305 306 if (_value == "/") 307 ret._value = rhs._value; 308 else 309 ret._value = _value ~ rhs._value; 310 311 return ret; 312 } 313 314 void opOpAssign(string op : "~")(string rhs) pure @safe { 315 _value = opBinary!"~"(rhs)._value; 316 } 317 318 void opOpAssign(string op : "~")(ObjectPath rhs) pure @safe { 319 _value = opBinary!"~"(rhs)._value; 320 } 321 322 /++ 323 Returns: `false` for empty strings or strings that don't match the 324 pattern `(/[0-9A-Za-z_]+)+|/`. 325 +/ 326 static bool isValid(string objPath) pure @nogc nothrow @safe { 327 import std.ascii : isAlphaNum; 328 329 if (!objPath.length) 330 return false; 331 if (objPath == "/") 332 return true; 333 if (objPath[0] != '/' || objPath[$ - 1] == '/') 334 return false; 335 // .representation to avoid unicode exceptions -> @nogc & nothrow 336 return objPath.representation.splitter('/').drop(1) 337 .all!(a => 338 a.length && 339 a.all!(c => 340 c.isAlphaNum || c == '_' 341 ) 342 ); 343 } 344 } 345 346 /// Structure allowing typeless parameters 347 struct DBusAny { 348 /// DBus type of the value (never 'v'), see typeSig!T 349 int type; 350 /// Child signature for Arrays & Tuples 351 string signature; 352 /// If true, this value will get serialized as variant value, otherwise it is serialized like it wasn't in a DBusAny wrapper. 353 /// Same functionality as Variant!T but with dynamic types if true. 354 bool explicitVariant; 355 356 union 357 { 358 /// 359 byte int8; 360 /// 361 short int16; 362 /// 363 ushort uint16; 364 /// 365 int int32; 366 /// 367 uint uint32; 368 /// 369 long int64; 370 /// 371 ulong uint64; 372 /// 373 double float64; 374 /// 375 string str; 376 /// 377 bool boolean; 378 /// 379 ObjectPath obj; 380 /// 381 DBusAny[] array; 382 /// 383 alias tuple = array; 384 /// 385 DictionaryEntry!(DBusAny, DBusAny)* entry; 386 /// 387 ubyte[] binaryData; 388 } 389 390 /// Manually creates a DBusAny object using a type, signature and implicit specifier. 391 this(int type, string signature, bool explicit) { 392 this.type = type; 393 this.signature = signature; 394 this.explicitVariant = explicit; 395 } 396 397 /// Automatically creates a DBusAny object with fitting parameters from a D type or Variant!T. 398 /// Pass a `Variant!T` to make this an explicit variant. 399 this(T)(T value) { 400 static if(is(T == byte) || is(T == ubyte)) { 401 this(typeCode!byte, null, false); 402 int8 = cast(byte) value; 403 } else static if(is(T == short)) { 404 this(typeCode!short, null, false); 405 int16 = cast(short) value; 406 } else static if(is(T == ushort)) { 407 this(typeCode!ushort, null, false); 408 uint16 = cast(ushort) value; 409 } else static if(is(T == int)) { 410 this(typeCode!int, null, false); 411 int32 = cast(int) value; 412 } else static if(is(T == uint)) { 413 this(typeCode!uint, null, false); 414 uint32 = cast(uint) value; 415 } else static if(is(T == long)) { 416 this(typeCode!long, null, false); 417 int64 = cast(long) value; 418 } else static if(is(T == ulong)) { 419 this(typeCode!ulong, null, false); 420 uint64 = cast(ulong) value; 421 } else static if(is(T == double)) { 422 this(typeCode!double, null, false); 423 float64 = cast(double) value; 424 } else static if(isSomeString!T) { 425 this(typeCode!string, null, false); 426 str = value.to!string; 427 } else static if(is(T == bool)) { 428 this(typeCode!bool, null, false); 429 boolean = cast(bool) value; 430 } else static if(is(T == ObjectPath)) { 431 this(typeCode!ObjectPath, null, false); 432 obj = value; 433 } else static if(is(T == Variant!R, R)) { 434 static if(is(R == DBusAny)) { 435 type = value.data.type; 436 signature = value.data.signature; 437 explicitVariant = true; 438 if(type == 'a' || type == 'r') { 439 if(signature == ['y']) 440 binaryData = value.data.binaryData; 441 else 442 array = value.data.array; 443 } else if(type == 's') 444 str = value.data.str; 445 else if(type == 'e') 446 entry = value.data.entry; 447 else 448 uint64 = value.data.uint64; 449 } else { 450 this(value.data); 451 explicitVariant = true; 452 } 453 } else static if(is(T : DictionaryEntry!(K, V), K, V)) { 454 this('e', null, false); 455 entry = new DictionaryEntry!(DBusAny, DBusAny)(); 456 static if(is(K == DBusAny)) 457 entry.key = value.key; 458 else 459 entry.key = DBusAny(value.key); 460 static if(is(V == DBusAny)) 461 entry.value = value.value; 462 else 463 entry.value = DBusAny(value.value); 464 } else static if(is(T == ubyte[]) || is(T == byte[])) { 465 this('a', ['y'], false); 466 binaryData = cast(ubyte[]) value; 467 } else static if(isInputRange!T) { 468 this.type = 'a'; 469 static assert(!is(ElementType!T == DBusAny), "Array must consist of the same type, use Variant!DBusAny or DBusAny(tuple(...)) instead"); 470 static assert(.typeSig!(ElementType!T) != "y"); 471 this.signature = .typeSig!(ElementType!T); 472 this.explicitVariant = false; 473 foreach(elem; value) 474 array ~= DBusAny(elem); 475 } else static if(isTuple!T) { 476 this.type = 'r'; 477 this.signature = ['(']; 478 this.explicitVariant = false; 479 foreach(index, R; value.Types) { 480 auto var = DBusAny(value[index]); 481 tuple ~= var; 482 if(var.explicitVariant) 483 this.signature ~= 'v'; 484 else { 485 if (var.type != 'r') 486 this.signature ~= cast(char) var.type; 487 if(var.type == 'a' || var.type == 'r') 488 this.signature ~= var.signature; 489 } 490 } 491 this.signature ~= ')'; 492 } else static if(isAssociativeArray!T) { 493 this(value.byDictionaryEntries); 494 } else static assert(false, T.stringof ~ " not convertible to a Variant"); 495 } 496 497 /// 498 string toString() const { 499 string valueStr; 500 switch(type) { 501 case typeCode!byte: 502 valueStr = int8.to!string; 503 break; 504 case typeCode!short: 505 valueStr = int16.to!string; 506 break; 507 case typeCode!ushort: 508 valueStr = uint16.to!string; 509 break; 510 case typeCode!int: 511 valueStr = int32.to!string; 512 break; 513 case typeCode!uint: 514 valueStr = uint32.to!string; 515 break; 516 case typeCode!long: 517 valueStr = int64.to!string; 518 break; 519 case typeCode!ulong: 520 valueStr = uint64.to!string; 521 break; 522 case typeCode!double: 523 valueStr = float64.to!string; 524 break; 525 case typeCode!string: 526 valueStr = '"' ~ str ~ '"'; 527 break; 528 case typeCode!ObjectPath: 529 valueStr = '"' ~ obj.to!string ~ '"'; 530 break; 531 case typeCode!bool: 532 valueStr = boolean ? "true" : "false"; 533 break; 534 case 'a': 535 import std.digest : toHexString; 536 537 if(signature == ['y']) 538 valueStr = "binary(" ~ binaryData.toHexString ~ ')'; 539 else 540 valueStr = '[' ~ array.map!(a => a.toString).join(", ") ~ ']'; 541 break; 542 case 'r': 543 valueStr = '(' ~ tuple.map!(a => a.toString).join(", ") ~ ')'; 544 break; 545 case 'e': 546 valueStr = entry.key.toString ~ ": " ~ entry.value.toString; 547 break; 548 default: 549 valueStr = "unknown"; 550 break; 551 } 552 return "DBusAny(" ~ cast(char) type 553 ~ ", \"" ~ signature.idup 554 ~ "\", " ~ (explicitVariant ? "explicit" : "implicit") 555 ~ ", " ~ valueStr ~ ")"; 556 } 557 558 /++ 559 Get the value stored in the DBusAny object. 560 561 Parameters: 562 T = The requested type. The currently stored value must match the 563 requested type exactly. 564 565 Returns: 566 The current value of the DBusAny object. 567 568 Throws: 569 TypeMismatchException if the DBus type of the current value of the 570 DBusAny object is not the same as the DBus type used to represent T. 571 +/ 572 T get(T)() @property const 573 if(staticIndexOf!(T, BasicTypes) >= 0) 574 { 575 enforce(type == typeCode!T, 576 new TypeMismatchException( 577 "Cannot get a " ~ T.stringof ~ " from a DBusAny with" 578 ~ " a value of DBus type '" ~ typeSig ~ "'.", typeCode!T, type)); 579 580 static if(isIntegral!T) { 581 enum memberName = 582 (isUnsigned!T ? "uint" : "int") ~ (T.sizeof * 8).to!string; 583 return __traits(getMember, this, memberName); 584 } else static if(is(T == double)) { 585 return float64; 586 } else static if(is(T == string)) { 587 return str; 588 } else static if(is(T == ObjectPath)) { 589 return obj; 590 } else static if(is(T == bool)) { 591 return boolean; 592 } else { 593 static assert(false); 594 } 595 } 596 597 /// ditto 598 T get(T)() @property const 599 if(is(T == const(DBusAny)[])) 600 { 601 enforce((type == 'a' && signature != "y") || type == 'r', 602 new TypeMismatchException( 603 "Cannot get a " ~ T.stringof ~ " from a DBusAny with" 604 ~ " a value of DBus type '" ~ this.typeSig ~ "'.", 605 typeCode!T, type)); 606 607 return array; 608 } 609 610 /// ditto 611 T get(T)() @property const 612 if (is(T == const(ubyte)[])) 613 { 614 enforce(type == 'a' && signature == "y", 615 new TypeMismatchException( 616 "Cannot get a " ~ T.stringof ~ " from a DBusAny with" 617 ~ " a value of DBus type '" ~ this.typeSig ~ "'.", 618 typeCode!T, type)); 619 620 return binaryData; 621 } 622 623 /// If the value is an array of DictionaryEntries this will return a HashMap 624 DBusAny[DBusAny] toAA() { 625 enforce(type == 'a' && signature && signature[0] == '{'); 626 DBusAny[DBusAny] aa; 627 foreach(val; array) { 628 enforce(val.type == 'e'); 629 aa[val.entry.key] = val.entry.value; 630 } 631 return aa; 632 } 633 634 /++ 635 Get the DBus type signature of the value stored in the DBusAny object. 636 637 Returns: 638 The type signature of the value stored in this DBusAny object. 639 +/ 640 string typeSig() @property const pure nothrow @safe 641 { 642 if(type == 'a') { 643 return "a" ~ signature; 644 } else if(type == 'r') { 645 return signature; 646 } else if(type == 'e') { 647 return () @trusted { 648 return "{" ~ entry.key.signature ~ entry.value.signature ~ "}"; 649 } (); 650 } else { 651 return [ cast(char) type ]; 652 } 653 } 654 655 /// Converts a basic type, a tuple or an array to the D type with type checking. Tuples can get converted to an array too. 656 T to(T)() { 657 static if(is(T == Variant!R, R)) { 658 static if(is(R == DBusAny)) { 659 auto v = to!R; 660 v.explicitVariant = false; 661 return Variant!R(v); 662 } else 663 return Variant!R(to!R); 664 } else static if(is(T == DBusAny)) { 665 return this; 666 } else static if(isIntegral!T || isFloatingPoint!T) { 667 switch(type) { 668 case typeCode!byte: 669 return cast(T) int8; 670 case typeCode!short: 671 return cast(T) int16; 672 case typeCode!ushort: 673 return cast(T) uint16; 674 case typeCode!int: 675 return cast(T) int32; 676 case typeCode!uint: 677 return cast(T) uint32; 678 case typeCode!long: 679 return cast(T) int64; 680 case typeCode!ulong: 681 return cast(T) uint64; 682 case typeCode!double: 683 return cast(T) float64; 684 default: 685 throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof); 686 } 687 } else static if(is(T == bool)) { 688 if(type == 'b') 689 return boolean; 690 else 691 throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof); 692 } else static if(isSomeString!T) { 693 if(type == 's') 694 return str.to!T; 695 else if(type == 'o') 696 return obj.toString(); 697 else 698 throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof); 699 } else static if(is(T == ObjectPath)) { 700 if(type == 'o') 701 return obj; 702 else 703 throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof); 704 } else static if(isDynamicArray!T) { 705 if(type != 'a' && type != 'r') 706 throw new Exception("Can't convert type " ~ cast(char) type ~ " to an array"); 707 T ret; 708 if(signature == ['y']) { 709 static if(isIntegral!(ElementType!T)) 710 foreach(elem; binaryData) 711 ret ~= elem.to!(ElementType!T); 712 } else 713 foreach(elem; array) 714 ret ~= elem.to!(ElementType!T); 715 return ret; 716 } else static if(isTuple!T) { 717 if(type != 'r') 718 throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof); 719 T ret; 720 enforce(ret.Types.length == tuple.length, "Tuple length mismatch"); 721 foreach(index, T; ret.Types) 722 ret[index] = tuple[index].to!T; 723 return ret; 724 } else static if(isAssociativeArray!T) { 725 if(type != 'a' || !signature || signature[0] != '{') 726 throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof); 727 T ret; 728 foreach(pair; array) { 729 enforce(pair.type == 'e'); 730 ret[pair.entry.key.to!(KeyType!T)] = pair.entry.value.to!(ValueType!T); 731 } 732 return ret; 733 } else static assert(false, "Can't convert variant to " ~ T.stringof); 734 } 735 736 bool opEquals(ref in DBusAny b) const { 737 if(b.type != type || b.explicitVariant != explicitVariant) 738 return false; 739 if((type == 'a' || type == 'r') && b.signature != signature) 740 return false; 741 if(type == 'a' && signature == ['y']) 742 return binaryData == b.binaryData; 743 if(type == 'a') 744 return array == b.array; 745 else if(type == 'r') 746 return tuple == b.tuple; 747 else if(type == 's') 748 return str == b.str; 749 else if(type == 'o') 750 return obj == b.obj; 751 else if(type == 'e') 752 return entry == b.entry || (entry && b.entry && *entry == *b.entry); 753 else 754 return uint64 == b.uint64; 755 } 756 } 757 758 /// Marks the data as variant on serialization 759 struct Variant(T) { 760 /// 761 T data; 762 } 763 764 Variant!T variant(T)(T data) { 765 return Variant!T(data); 766 } 767 768 enum MessageType { 769 Invalid = 0, 770 Call, Return, Error, Signal 771 } 772 773 void emitSignal(Args...)(Connection conn, string path, string iface, string name, Args args) { 774 Message msg = Message(null, path, iface, name, true); 775 msg.build(args); 776 conn.send(msg); 777 } 778 779 struct Message { 780 DBusMessage *msg; 781 782 this(string dest, string path, string iface, string method, bool signal = false) { 783 if(signal) 784 msg = dbus_message_new_signal(path.toStringz(), iface.toStringz(), method.toStringz()); 785 else 786 msg = dbus_message_new_method_call(dest.toStringz(), path.toStringz(), iface.toStringz(), method.toStringz()); 787 } 788 789 this(DBusMessage *m) { 790 msg = m; 791 } 792 793 this(this) { 794 dbus_message_ref(msg); 795 } 796 797 ~this() { 798 dbus_message_unref(msg); 799 } 800 801 void build(TS...)(TS args) if(allCanDBus!TS) { 802 DBusMessageIter iter; 803 dbus_message_iter_init_append(msg, &iter); 804 buildIter(&iter, args); 805 } 806 807 /** 808 Reads the first argument of the message. 809 Note that this creates a new iterator every time so calling it multiple times will always 810 read the first argument. This is suitable for single item returns. 811 To read multiple arguments use readTuple. 812 */ 813 T read(T)() if(canDBus!T) { 814 DBusMessageIter iter; 815 dbus_message_iter_init(msg, &iter); 816 return readIter!T(&iter); 817 } 818 alias read to; 819 820 Tup readTuple(Tup)() if(isTuple!Tup && allCanDBus!(Tup.Types)) { 821 DBusMessageIter iter; 822 dbus_message_iter_init(msg, &iter); 823 Tup ret; 824 readIterTuple(&iter, ret); 825 return ret; 826 } 827 828 Message createReturn() { 829 return Message(dbus_message_new_method_return(msg)); 830 } 831 832 MessageType type() { 833 return cast(MessageType)dbus_message_get_type(msg); 834 } 835 836 bool isCall() { 837 return type() == MessageType.Call; 838 } 839 840 // Various string members 841 // TODO: make a mixin to avoid this copy-paste 842 string signature() { 843 const(char)* cStr = dbus_message_get_signature(msg); 844 assert(cStr != null); 845 return cStr.fromStringz().idup; 846 } 847 string path() { 848 const(char)* cStr = dbus_message_get_path(msg); 849 assert(cStr != null); 850 return cStr.fromStringz().idup; 851 } 852 string iface() { 853 const(char)* cStr = dbus_message_get_interface(msg); 854 assert(cStr != null); 855 return cStr.fromStringz().idup; 856 } 857 string member() { 858 const(char)* cStr = dbus_message_get_member(msg); 859 assert(cStr != null); 860 return cStr.fromStringz().idup; 861 } 862 string sender() { 863 const(char)* cStr = dbus_message_get_sender(msg); 864 assert(cStr != null); 865 return cStr.fromStringz().idup; 866 } 867 } 868 869 struct Connection { 870 DBusConnection *conn; 871 this(DBusConnection *connection) { 872 conn = connection; 873 } 874 875 this(this) { 876 dbus_connection_ref(conn); 877 } 878 879 ~this() { 880 dbus_connection_unref(conn); 881 } 882 883 void close() { 884 dbus_connection_close(conn); 885 } 886 887 void send(Message msg) { 888 dbus_connection_send(conn,msg.msg, null); 889 } 890 891 void sendBlocking(Message msg) { 892 send(msg); 893 dbus_connection_flush(conn); 894 } 895 896 Message sendWithReplyBlocking(Message msg, int timeout = -1) { 897 DBusMessage *dbusMsg = msg.msg; 898 dbus_message_ref(dbusMsg); 899 DBusMessage *reply = wrapErrors((err) { 900 auto ret = dbus_connection_send_with_reply_and_block(conn,dbusMsg,timeout,err); 901 dbus_message_unref(dbusMsg); 902 return ret; 903 }); 904 return Message(reply); 905 } 906 907 Message sendWithReplyBlocking(Message msg, Duration timeout) { 908 return sendWithReplyBlocking(msg, timeout.total!"msecs"().to!int); 909 } 910 } 911 912 Connection connectToBus(DBusBusType bus = DBusBusType.DBUS_BUS_SESSION) { 913 DBusConnection *conn = wrapErrors((err) { return dbus_bus_get(bus,err); }); 914 return Connection(conn); 915 } 916 917 class PathIface { 918 this(Connection conn, string dest, ObjectPath path, string iface) { 919 this(conn, dest, path.value, iface); 920 } 921 922 this(Connection conn, string dest, string path, string iface) { 923 this.conn = conn; 924 this.dest = dest.toStringz(); 925 this.path = path.toStringz(); 926 this.iface = iface.toStringz(); 927 } 928 929 Ret call(Ret, Args...)(string meth, Args args) if(allCanDBus!Args && canDBus!Ret) { 930 Message msg = Message(dbus_message_new_method_call(dest,path,iface,meth.toStringz())); 931 msg.build(args); 932 Message ret = conn.sendWithReplyBlocking(msg); 933 return ret.read!Ret(); 934 } 935 936 Message opDispatch(string meth, Args...)(Args args) { 937 Message msg = Message(dbus_message_new_method_call(dest,path,iface,meth.toStringz())); 938 msg.build(args); 939 return conn.sendWithReplyBlocking(msg); 940 } 941 942 Connection conn; 943 const(char)* dest; 944 const(char)* path; 945 const(char)* iface; 946 } 947 948 enum SignalMethod; 949 950 /** 951 Registers all *possible* methods of an object in a router. 952 It will not register methods that use types that ddbus can't handle. 953 954 The implementation is rather hacky and uses the compiles trait to check for things 955 working so if some methods randomly don't seem to be added, you should probably use 956 setHandler on the router directly. It is also not efficient and creates a closure for every method. 957 958 TODO: replace this with something that generates a wrapper class who's methods take and return messages 959 and basically do what MessageRouter.setHandler does but avoiding duplication. Then this DBusWrapper!Class 960 could be instantiated with any object efficiently and placed in the router table with minimal duplication. 961 */ 962 void registerMethods(T : Object)(MessageRouter router, string path, string iface, T obj) { 963 MessagePattern patt = MessagePattern(path,iface,"",false); 964 foreach(member; __traits(allMembers, T)) { 965 static if (__traits(compiles, __traits(getOverloads, obj, member)) 966 && __traits(getOverloads, obj, member).length > 0 967 && __traits(compiles, router.setHandler(patt, &__traits(getOverloads,obj,member)[0]))) { 968 patt.method = member; 969 patt.signal = hasUDA!(__traits(getOverloads,obj,member)[0], SignalMethod); 970 router.setHandler(patt, &__traits(getOverloads,obj,member)[0]); 971 } 972 } 973 } 974 975 struct MessagePattern { 976 string path; 977 string iface; 978 string method; 979 bool signal; 980 981 this(Message msg) { 982 path = msg.path(); 983 iface = msg.iface(); 984 method = msg.member(); 985 signal = (msg.type() == MessageType.Signal); 986 } 987 988 this(string path, string iface, string method, bool signal = false) { 989 this.path = path; 990 this.iface = iface; 991 this.method = method; 992 this.signal = signal; 993 } 994 995 size_t toHash() const @safe nothrow { 996 size_t hash = 0; 997 auto stringHash = &(typeid(path).getHash); 998 hash += stringHash(&path); 999 hash += stringHash(&iface); 1000 hash += stringHash(&method); 1001 hash += (signal?1:0); 1002 return hash; 1003 } 1004 1005 bool opEquals(ref const typeof(this) s) const @safe pure nothrow { 1006 return (path == s.path) && (iface == s.iface) && (method == s.method) && (signal == s.signal); 1007 } 1008 } 1009 1010 struct MessageHandler { 1011 alias HandlerFunc = void delegate(Message call, Connection conn); 1012 HandlerFunc func; 1013 string[] argSig; 1014 string[] retSig; 1015 } 1016 1017 class MessageRouter { 1018 MessageHandler[MessagePattern] callTable; 1019 1020 bool handle(Message msg, Connection conn) { 1021 MessageType type = msg.type(); 1022 if(type != MessageType.Call && type != MessageType.Signal) 1023 return false; 1024 auto pattern = MessagePattern(msg); 1025 // import std.stdio; debug writeln("Handling ", pattern); 1026 1027 if(pattern.iface == "org.freedesktop.DBus.Introspectable" && 1028 pattern.method == "Introspect" && !pattern.signal) { 1029 handleIntrospect(pattern.path, msg, conn); 1030 return true; 1031 } 1032 1033 MessageHandler* handler = (pattern in callTable); 1034 if(handler is null) return false; 1035 1036 // Check for matching argument types 1037 version(DDBusNoChecking) { 1038 1039 } else { 1040 if(!equal(join(handler.argSig), msg.signature())) { 1041 return false; 1042 } 1043 } 1044 1045 handler.func(msg,conn); 1046 return true; 1047 } 1048 1049 void setHandler(Ret, Args...)(MessagePattern patt, Ret delegate(Args) handler) { 1050 void handlerWrapper(Message call, Connection conn) { 1051 Tuple!Args args = call.readTuple!(Tuple!Args)(); 1052 auto retMsg = call.createReturn(); 1053 static if(!is(Ret == void)) { 1054 Ret ret = handler(args.expand); 1055 static if (is(Ret == Tuple!T, T...)) 1056 retMsg.build!T(ret.expand); 1057 else 1058 retMsg.build(ret); 1059 } else { 1060 handler(args.expand); 1061 } 1062 if(!patt.signal) 1063 conn.send(retMsg); 1064 } 1065 static string[] args = typeSigArr!Args; 1066 static if(is(Ret==void)) { 1067 static string[] ret = []; 1068 } else { 1069 static string[] ret = typeSigReturn!Ret; 1070 } 1071 MessageHandler handleStruct = {func: &handlerWrapper, argSig: args, retSig: ret}; 1072 callTable[patt] = handleStruct; 1073 } 1074 1075 static string introspectHeader = `<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> 1076 <node name="%s">`; 1077 1078 string introspectXML(string path) { 1079 auto methods = callTable.byKey().filter!(a => (a.path == path) && !a.signal)().array() 1080 // .schwartzSort!((a) => a.iface, "a<b")(); 1081 .sort!((a,b) => a.iface < b.iface)(); 1082 auto ifaces = methods.groupBy(); 1083 auto app = appender!string; 1084 formattedWrite(app,introspectHeader,path); 1085 foreach(iface; ifaces) { 1086 formattedWrite(app,`<interface name="%s">`,iface.front.iface); 1087 foreach(methodPatt; iface.array()) { 1088 formattedWrite(app,`<method name="%s">`,methodPatt.method); 1089 auto handler = callTable[methodPatt]; 1090 foreach(arg; handler.argSig) { 1091 formattedWrite(app,`<arg type="%s" direction="in"/>`,arg); 1092 } 1093 foreach(arg; handler.retSig) { 1094 formattedWrite(app,`<arg type="%s" direction="out"/>`,arg); 1095 } 1096 app.put("</method>"); 1097 } 1098 app.put("</interface>"); 1099 } 1100 1101 string childPath = path; 1102 if(!childPath.endsWith("/")) { 1103 childPath ~= "/"; 1104 } 1105 auto children = callTable.byKey().filter!(a => (a.path.startsWith(childPath)) && !a.signal)() 1106 .map!((s) => s.path.chompPrefix(childPath)) 1107 .map!((s) => s.splitter('/').front) 1108 .array().sort().uniq(); 1109 foreach(child; children) { 1110 formattedWrite(app,`<node name="%s"/>`,child); 1111 } 1112 1113 app.put("</node>"); 1114 return app.data; 1115 } 1116 1117 void handleIntrospect(string path, Message call, Connection conn) { 1118 auto retMsg = call.createReturn(); 1119 retMsg.build(introspectXML(path)); 1120 conn.sendBlocking(retMsg); 1121 } 1122 } 1123 1124 extern(C) private DBusHandlerResult filterFunc(DBusConnection *dConn, DBusMessage *dMsg, void *routerP) { 1125 MessageRouter router = cast(MessageRouter)routerP; 1126 dbus_message_ref(dMsg); 1127 Message msg = Message(dMsg); 1128 dbus_connection_ref(dConn); 1129 Connection conn = Connection(dConn); 1130 bool handled = router.handle(msg, conn); 1131 if(handled) { 1132 return DBusHandlerResult.DBUS_HANDLER_RESULT_HANDLED; 1133 } else { 1134 return DBusHandlerResult.DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 1135 } 1136 } 1137 1138 extern(C) private void unrootUserData(void *userdata) { 1139 GC.removeRoot(userdata); 1140 } 1141 1142 void registerRouter(Connection conn, MessageRouter router) { 1143 void *routerP = cast(void*)router; 1144 GC.addRoot(routerP); 1145 dbus_connection_add_filter(conn.conn, &filterFunc, routerP, &unrootUserData); 1146 } 1147 1148 private T wrapErrors(T)( 1149 T delegate(DBusError *err) del, 1150 string file = __FILE__, 1151 size_t line = __LINE__, 1152 Throwable next = null 1153 ) { 1154 DBusError error; 1155 dbus_error_init(&error); 1156 T ret = del(&error); 1157 if(dbus_error_is_set(&error)) { 1158 auto ex = new DBusException(&error, file, line, next); 1159 dbus_error_free(&error); 1160 throw ex; 1161 } 1162 return ret; 1163 } 1164 1165 /++ 1166 Thrown when a DBus error code was returned by libdbus. 1167 +/ 1168 class DBusException : Exception { 1169 private this( 1170 scope DBusError *err, 1171 string file = __FILE__, 1172 size_t line = __LINE__, 1173 Throwable next = null 1174 ) pure nothrow { 1175 1176 super(err.message.fromStringz().idup, file, line, next); 1177 } 1178 } 1179 1180 /++ 1181 Thrown when the signature of a message does not match the requested types or 1182 when trying to get a value from a DBusAny object that does not match the type 1183 of its actual value. 1184 +/ 1185 class TypeMismatchException : Exception { 1186 private this( 1187 int expectedType, 1188 int actualType, 1189 string file = __FILE__, 1190 size_t line = __LINE__, 1191 Throwable next = null 1192 ) pure nothrow @safe { 1193 string message; 1194 1195 if (expectedType == 'v') { 1196 message = "The type of value at the current position in the message is" 1197 ~ " incompatible to the target variant type." 1198 ~ " Type code of the value: '" ~ cast(char) actualType ~ '\''; 1199 } else { 1200 message = "The type of value at the current position in the message does" 1201 ~ " not match the type of value to be read." 1202 ~ " Expected: '" ~ cast(char) expectedType ~ "'," 1203 ~ " Got: '" ~ cast(char) actualType ~ '\''; 1204 } 1205 1206 this(message, expectedType, actualType, file, line, next); 1207 } 1208 1209 this( 1210 string message, 1211 int expectedType, 1212 int actualType, 1213 string file = __FILE__, 1214 size_t line = __LINE__, 1215 Throwable next = null 1216 ) pure nothrow @safe { 1217 _expectedType = expectedType; 1218 _actualType = actualType; 1219 super(message, file, line, next); 1220 } 1221 1222 int expectedType() @property pure const nothrow @safe @nogc { 1223 return _expectedType; 1224 } 1225 1226 int actualType() @property pure const nothrow @safe @nogc { 1227 return _actualType; 1228 } 1229 1230 private: 1231 int _expectedType; 1232 int _actualType; 1233 } 1234 1235 /++ 1236 Thrown during type conversion between DBus types and D types when a value is 1237 encountered that can not be represented in the target type. 1238 1239 This exception should not normally be thrown except when dealing with D types 1240 that have a constrained value set, such as Enums. 1241 +/ 1242 class InvalidValueException : Exception { 1243 private this(Source)( 1244 Source value, 1245 string targetType, 1246 string file = __FILE__, 1247 size_t line = __LINE__, 1248 Throwable next = null 1249 ) { 1250 import std.conv : to; 1251 1252 static if(__traits(compiles, value.to!string)) 1253 string valueString = value.to!string; 1254 else 1255 string valueString = "(unprintable)"; 1256 1257 super("Value " ~ valueString ~ " cannot be represented in type " ~ targetType); 1258 } 1259 } 1260 1261 import std.exception : enforce; 1262 import std.meta: allSatisfy; 1263 import std.range; 1264 import std.traits; 1265 import std.variant : VariantN; 1266 1267 void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { 1268 foreach(index, arg; args) { 1269 alias TS[index] T; 1270 static if(is(T == string)) { 1271 immutable(char)* cStr = arg.toStringz(); 1272 dbus_message_iter_append_basic(iter,typeCode!T,&cStr); 1273 } else static if(is(T == ObjectPath)) { 1274 immutable(char)* cStr = arg.toString().toStringz(); 1275 dbus_message_iter_append_basic(iter,typeCode!T,&cStr); 1276 } else static if(is(T==bool)) { 1277 dbus_bool_t longerBool = arg; // dbus bools are ints 1278 dbus_message_iter_append_basic(iter,typeCode!T,&longerBool); 1279 } else static if(isTuple!T) { 1280 DBusMessageIter sub; 1281 dbus_message_iter_open_container(iter, 'r', null, &sub); 1282 buildIter(&sub, arg.expand); 1283 dbus_message_iter_close_container(iter, &sub); 1284 } else static if(isInputRange!T) { 1285 DBusMessageIter sub; 1286 const(char)* subSig = (typeSig!(ElementType!T)()).toStringz(); 1287 dbus_message_iter_open_container(iter, 'a', subSig, &sub); 1288 foreach(x; arg) { 1289 static if(isInstanceOf!(DictionaryEntry, typeof(x))) { 1290 DBusMessageIter entry; 1291 dbus_message_iter_open_container(&sub, 'e', null, &entry); 1292 buildIter(&entry, x.key); 1293 buildIter(&entry, x.value); 1294 dbus_message_iter_close_container(&sub, &entry); 1295 } else { 1296 buildIter(&sub, x); 1297 } 1298 } 1299 dbus_message_iter_close_container(iter, &sub); 1300 } else static if(isAssociativeArray!T) { 1301 DBusMessageIter sub; 1302 const(char)* subSig = typeSig!T[1..$].toStringz(); 1303 dbus_message_iter_open_container(iter, 'a', subSig, &sub); 1304 foreach(k, v; arg) { 1305 DBusMessageIter entry; 1306 dbus_message_iter_open_container(&sub, 'e', null, &entry); 1307 buildIter(&entry, k); 1308 buildIter(&entry, v); 1309 dbus_message_iter_close_container(&sub, &entry); 1310 } 1311 dbus_message_iter_close_container(iter, &sub); 1312 } else static if(isInstanceOf!(VariantN, T)) { 1313 enforce(arg.hasValue, 1314 new InvalidValueException(arg, "dbus:" ~ cast(char) typeCode!T)); 1315 1316 DBusMessageIter sub; 1317 foreach(AT; T.AllowedTypes) { 1318 if (arg.peek!AT) { 1319 dbus_message_iter_open_container(iter, 'v', typeSig!AT.ptr, &sub); 1320 buildIter(&sub, arg.get!AT); 1321 dbus_message_iter_close_container(iter, &sub); 1322 break; 1323 } 1324 } 1325 } else static if(is(T == DBusAny) || is(T == Variant!DBusAny)) { 1326 static if(is(T == Variant!DBusAny)) { 1327 auto val = arg.data; 1328 val.explicitVariant = true; 1329 } else { 1330 auto val = arg; 1331 } 1332 DBusMessageIter subStore; 1333 DBusMessageIter* sub = &subStore; 1334 const(char)[] sig = [ cast(char) val.type ]; 1335 if(val.type == 'a') 1336 sig ~= val.signature; 1337 else if(val.type == 'r') 1338 sig = val.signature; 1339 sig ~= '\0'; 1340 if (!val.explicitVariant) 1341 sub = iter; 1342 else 1343 dbus_message_iter_open_container(iter, 'v', sig.ptr, sub); 1344 if(val.type == 's') { 1345 buildIter(sub, val.str); 1346 } else if(val.type == 'o') { 1347 buildIter(sub, val.obj); 1348 } else if(val.type == 'b') { 1349 buildIter(sub,val.boolean); 1350 } else if(dbus_type_is_basic(val.type)) { 1351 dbus_message_iter_append_basic(sub,val.type,&val.int64); 1352 } else if(val.type == 'a') { 1353 DBusMessageIter arr; 1354 dbus_message_iter_open_container(sub, 'a', sig[1 .. $].ptr, &arr); 1355 if (val.signature == ['y']) 1356 foreach (item; val.binaryData) 1357 dbus_message_iter_append_basic(&arr, 'y', &item); 1358 else 1359 foreach(item; val.array) 1360 buildIter(&arr, item); 1361 dbus_message_iter_close_container(sub, &arr); 1362 } else if(val.type == 'r') { 1363 DBusMessageIter arr; 1364 dbus_message_iter_open_container(sub, 'r', null, &arr); 1365 foreach(item; val.tuple) 1366 buildIter(&arr, item); 1367 dbus_message_iter_close_container(sub, &arr); 1368 } else if(val.type == 'e') { 1369 DBusMessageIter entry; 1370 dbus_message_iter_open_container(sub, 'e', null, &entry); 1371 buildIter(&entry, val.entry.key); 1372 buildIter(&entry, val.entry.value); 1373 dbus_message_iter_close_container(sub, &entry); 1374 } 1375 if(val.explicitVariant) 1376 dbus_message_iter_close_container(iter, sub); 1377 } else static if(isInstanceOf!(Variant, T)) { 1378 DBusMessageIter sub; 1379 const(char)* subSig = typeSig!(VariantType!T).toStringz(); 1380 dbus_message_iter_open_container(iter, 'v', subSig, &sub); 1381 buildIter(&sub, arg.data); 1382 dbus_message_iter_close_container(iter, &sub); 1383 } else static if(is(T == struct)) { 1384 DBusMessageIter sub; 1385 dbus_message_iter_open_container(iter, 'r', null, &sub); 1386 1387 // Following failed because of missing 'this' for members of arg. 1388 // That sucks. It worked without Filter. 1389 // Reported: https://issues.dlang.org/show_bug.cgi?id=17692 1390 // buildIter(&sub, Filter!(isAllowedField, arg.tupleof)); 1391 1392 // Using foreach to work around the issue 1393 foreach(i, member; arg.tupleof) { 1394 // Ugly, but we need to use tupleof again in the condition, because when 1395 // we use `member`, isAllowedField will fail because it'll find this 1396 // nice `buildIter` function instead of T when it looks up the parent 1397 // scope of its argument. 1398 static if (isAllowedField!(arg.tupleof[i])) 1399 buildIter(&sub, member); 1400 } 1401 1402 dbus_message_iter_close_container(iter, &sub); 1403 } else static if(basicDBus!T) { 1404 dbus_message_iter_append_basic(iter,typeCode!T,&arg); 1405 } 1406 } 1407 } 1408 1409 T readIter(T)(DBusMessageIter *iter) if (is(T == enum)) { 1410 import std.algorithm.searching : canFind; 1411 1412 alias OriginalType!T B; 1413 1414 B value = readIter!B(iter); 1415 enforce( 1416 only(EnumMembers!T).canFind(value), 1417 new InvalidValueException(value, T.stringof) 1418 ); 1419 return cast(T) value; 1420 } 1421 1422 T readIter(T)(DBusMessageIter *iter) if (isInstanceOf!(BitFlags, T)) { 1423 import std.algorithm.iteration : fold; 1424 1425 alias TemplateArgsOf!T[0] E; 1426 alias OriginalType!E B; 1427 1428 B mask = only(EnumMembers!E).fold!((a, b) => cast(B) (a | b)); 1429 1430 B value = readIter!B(iter); 1431 enforce( 1432 !(value & ~mask), 1433 new InvalidValueException(value, T.stringof) 1434 ); 1435 1436 return T(cast(E) value); 1437 } 1438 1439 T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFlags, T) && canDBus!T) { 1440 auto argType = dbus_message_iter_get_arg_type(iter); 1441 T ret; 1442 1443 static if(!isInstanceOf!(Variant, T) || is(T == Variant!DBusAny)) { 1444 if(argType == 'v') { 1445 DBusMessageIter sub; 1446 dbus_message_iter_recurse(iter, &sub); 1447 static if(is(T == Variant!DBusAny)) { 1448 ret = variant(readIter!DBusAny(&sub)); 1449 } else { 1450 ret = readIter!T(&sub); 1451 static if(is(T == DBusAny)) 1452 ret.explicitVariant = true; 1453 } 1454 dbus_message_iter_next(iter); 1455 return ret; 1456 } 1457 } 1458 1459 static if( 1460 !is(T == DBusAny) 1461 && !is(T == Variant!DBusAny) 1462 && !isInstanceOf!(VariantN, T) 1463 ) { 1464 enforce(argType == typeCode!T(), 1465 new TypeMismatchException(typeCode!T(), argType)); 1466 } 1467 static if(is(T==string) || is(T==ObjectPath)) { 1468 const(char)* cStr; 1469 dbus_message_iter_get_basic(iter, &cStr); 1470 string str = cStr.fromStringz().idup; // copy string 1471 static if(is(T==string)) 1472 ret = str; 1473 else 1474 ret = ObjectPath(str); 1475 } else static if(is(T==bool)) { 1476 dbus_bool_t longerBool; 1477 dbus_message_iter_get_basic(iter, &longerBool); 1478 ret = cast(bool)longerBool; 1479 } else static if(isTuple!T) { 1480 DBusMessageIter sub; 1481 dbus_message_iter_recurse(iter, &sub); 1482 readIterTuple!T(&sub, ret); 1483 } else static if(is(T t : U[], U)) { 1484 assert(dbus_message_iter_get_element_type(iter) == typeCode!U); 1485 DBusMessageIter sub; 1486 dbus_message_iter_recurse(iter, &sub); 1487 while(dbus_message_iter_get_arg_type(&sub) != 0) { 1488 static if(is(U == DictionaryEntry!(K,V), K, V)) { 1489 DBusMessageIter entry; 1490 dbus_message_iter_recurse(&sub, &entry); 1491 ret ~= U(readIter!K(&entry), readIter!V(&entry)); 1492 dbus_message_iter_next(&sub); 1493 } else { 1494 ret ~= readIter!U(&sub); 1495 } 1496 } 1497 } else static if(isInstanceOf!(Variant, T)) { 1498 DBusMessageIter sub; 1499 dbus_message_iter_recurse(iter, &sub); 1500 ret.data = readIter!(VariantType!T)(&sub); 1501 } else static if(isInstanceOf!(VariantN, T)) { 1502 scope const(char)[] argSig = 1503 dbus_message_iter_get_signature(iter).fromStringz(); 1504 scope(exit) 1505 dbus_free(cast(void*) argSig.ptr); 1506 1507 foreach(AT; T.AllowedTypes) { 1508 // We have to compare the full signature here, not just the typecode. 1509 // Otherwise, in case of container types, we might select the wrong one. 1510 // We would then be calling an incorrect instance of readIter, which would 1511 // probably throw a TypeMismatchException. 1512 if (typeSig!AT == argSig) { 1513 ret = readIter!AT(iter); 1514 break; 1515 } 1516 } 1517 1518 // If no value is in ret, apparently none of the types matched. 1519 enforce(ret.hasValue, new TypeMismatchException(typeCode!T, argType)); 1520 } else static if(isAssociativeArray!T) { 1521 DBusMessageIter sub; 1522 dbus_message_iter_recurse(iter, &sub); 1523 while(dbus_message_iter_get_arg_type(&sub) != 0) { 1524 DBusMessageIter entry; 1525 dbus_message_iter_recurse(&sub, &entry); 1526 auto k = readIter!(KeyType!T)(&entry); 1527 auto v = readIter!(ValueType!T)(&entry); 1528 ret[k] = v; 1529 dbus_message_iter_next(&sub); 1530 } 1531 } else static if(is(T == DBusAny)) { 1532 ret.type = argType; 1533 ret.explicitVariant = false; 1534 if(ret.type == 's') { 1535 ret.str = readIter!string(iter); 1536 return ret; 1537 } else if(ret.type == 'o') { 1538 ret.obj = readIter!ObjectPath(iter); 1539 return ret; 1540 } else if(ret.type == 'b') { 1541 ret.boolean = readIter!bool(iter); 1542 return ret; 1543 } else if(dbus_type_is_basic(ret.type)) { 1544 dbus_message_iter_get_basic(iter, &ret.int64); 1545 } else if(ret.type == 'a') { 1546 DBusMessageIter sub; 1547 dbus_message_iter_recurse(iter, &sub); 1548 auto sig = dbus_message_iter_get_signature(&sub); 1549 ret.signature = sig.fromStringz.dup; 1550 dbus_free(sig); 1551 if (ret.signature == ['y']) 1552 while(dbus_message_iter_get_arg_type(&sub) != 0) { 1553 ubyte b; 1554 assert(dbus_message_iter_get_arg_type(&sub) == 'y'); 1555 dbus_message_iter_get_basic(&sub, &b); 1556 dbus_message_iter_next(&sub); 1557 ret.binaryData ~= b; 1558 } 1559 else 1560 while(dbus_message_iter_get_arg_type(&sub) != 0) { 1561 ret.array ~= readIter!DBusAny(&sub); 1562 } 1563 } else if(ret.type == 'r') { 1564 auto sig = dbus_message_iter_get_signature(iter); 1565 ret.signature = sig.fromStringz.dup; 1566 dbus_free(sig); 1567 DBusMessageIter sub; 1568 dbus_message_iter_recurse(iter, &sub); 1569 while(dbus_message_iter_get_arg_type(&sub) != 0) { 1570 ret.tuple ~= readIter!DBusAny(&sub); 1571 } 1572 } else if(ret.type == 'e') { 1573 DBusMessageIter sub; 1574 dbus_message_iter_recurse(iter, &sub); 1575 ret.entry = new DictionaryEntry!(DBusAny, DBusAny); 1576 ret.entry.key = readIter!DBusAny(&sub); 1577 ret.entry.value = readIter!DBusAny(&sub); 1578 } 1579 } else static if(is(T == struct)) { 1580 DBusMessageIter sub; 1581 dbus_message_iter_recurse(iter, &sub); 1582 readIterStruct!T(&sub, ret); 1583 } else static if(basicDBus!T) { 1584 dbus_message_iter_get_basic(iter, &ret); 1585 } 1586 1587 dbus_message_iter_next(iter); 1588 return ret; 1589 } 1590 1591 void readIterTuple(Tup)(DBusMessageIter *iter, ref Tup tuple) if(isTuple!Tup && allCanDBus!(Tup.Types)) { 1592 foreach(index, T; Tup.Types) { 1593 tuple[index] = readIter!T(iter); 1594 } 1595 } 1596 1597 void readIterStruct(S)(DBusMessageIter *iter, ref S s) if(is(S == struct) && canDBus!S) 1598 { 1599 foreach(index, T; Fields!S) { 1600 static if (isAllowedField!(s.tupleof[index])) { 1601 s.tupleof[index] = readIter!T(iter); 1602 } 1603 } 1604 } 1605 1606 import core.stdc.config; 1607 import core.stdc.stdarg; 1608 extern (C) { 1609 // START dbus/dbus-arch-deps.d 1610 alias c_long dbus_int64_t; 1611 alias c_ulong dbus_uint64_t; 1612 alias int dbus_int32_t; 1613 alias uint dbus_uint32_t; 1614 alias short dbus_int16_t; 1615 alias ushort dbus_uint16_t; 1616 // END dbus/dbus-arch-deps.d 1617 // START dbus/dbus-types.d 1618 alias uint dbus_unichar_t; 1619 alias uint dbus_bool_t; 1620 1621 1622 1623 struct DBus8ByteStruct 1624 { 1625 dbus_uint32_t first32; 1626 dbus_uint32_t second32; 1627 } 1628 1629 union DBusBasicValue 1630 { 1631 ubyte[8] bytes; 1632 dbus_int16_t i16; 1633 dbus_uint16_t u16; 1634 dbus_int32_t i32; 1635 dbus_uint32_t u32; 1636 dbus_bool_t bool_val; 1637 dbus_int64_t i64; 1638 dbus_uint64_t u64; 1639 DBus8ByteStruct eight; 1640 double dbl; 1641 ubyte byt; 1642 char* str; 1643 int fd; 1644 } 1645 // END dbus/dbus-types.d 1646 // START dbus/dbus-protocol.d 1647 1648 // END dbus/dbus-protocol.d 1649 // START dbus/dbus-errors.d 1650 struct DBusError 1651 { 1652 const(char)* name; 1653 const(char)* message; 1654 uint dummy1; 1655 uint dummy2; 1656 uint dummy3; 1657 uint dummy4; 1658 uint dummy5; 1659 void* padding1; 1660 } 1661 1662 void dbus_error_init (DBusError* error); 1663 void dbus_error_free (DBusError* error); 1664 void dbus_set_error (DBusError* error, const(char)* name, const(char)* message, ...); 1665 void dbus_set_error_const (DBusError* error, const(char)* name, const(char)* message); 1666 void dbus_move_error (DBusError* src, DBusError* dest); 1667 dbus_bool_t dbus_error_has_name (const(DBusError)* error, const(char)* name); 1668 dbus_bool_t dbus_error_is_set (const(DBusError)* error); 1669 // END dbus/dbus-errors.d 1670 // START dbus/dbus-macros.d 1671 1672 // END dbus/dbus-macros.d 1673 // START dbus/dbus-memory.d 1674 alias void function (void*) DBusFreeFunction; 1675 1676 void* dbus_malloc (size_t bytes); 1677 void* dbus_malloc0 (size_t bytes); 1678 void* dbus_realloc (void* memory, size_t bytes); 1679 void dbus_free (void* memory); 1680 void dbus_free_string_array (char** str_array); 1681 void dbus_shutdown (); 1682 // END dbus/dbus-memory.d 1683 // START dbus/dbus-shared.d 1684 enum DBusBusType 1685 { 1686 DBUS_BUS_SESSION = 0, 1687 DBUS_BUS_SYSTEM = 1, 1688 DBUS_BUS_STARTER = 2 1689 } 1690 1691 enum DBusHandlerResult 1692 { 1693 DBUS_HANDLER_RESULT_HANDLED = 0, 1694 DBUS_HANDLER_RESULT_NOT_YET_HANDLED = 1, 1695 DBUS_HANDLER_RESULT_NEED_MEMORY = 2 1696 } 1697 // END dbus/dbus-shared.d 1698 // START dbus/dbus-address.d 1699 struct DBusAddressEntry; 1700 1701 1702 dbus_bool_t dbus_parse_address (const(char)* address, DBusAddressEntry*** entry, int* array_len, DBusError* error); 1703 const(char)* dbus_address_entry_get_value (DBusAddressEntry* entry, const(char)* key); 1704 const(char)* dbus_address_entry_get_method (DBusAddressEntry* entry); 1705 void dbus_address_entries_free (DBusAddressEntry** entries); 1706 char* dbus_address_escape_value (const(char)* value); 1707 char* dbus_address_unescape_value (const(char)* value, DBusError* error); 1708 // END dbus/dbus-address.d 1709 // START dbus/dbus-syntax.d 1710 dbus_bool_t dbus_validate_path (const(char)* path, DBusError* error); 1711 dbus_bool_t dbus_validate_interface (const(char)* name, DBusError* error); 1712 dbus_bool_t dbus_validate_member (const(char)* name, DBusError* error); 1713 dbus_bool_t dbus_validate_error_name (const(char)* name, DBusError* error); 1714 dbus_bool_t dbus_validate_bus_name (const(char)* name, DBusError* error); 1715 dbus_bool_t dbus_validate_utf8 (const(char)* alleged_utf8, DBusError* error); 1716 // END dbus/dbus-syntax.d 1717 // START dbus/dbus-signature.d 1718 struct DBusSignatureIter 1719 { 1720 void* dummy1; 1721 void* dummy2; 1722 dbus_uint32_t dummy8; 1723 int dummy12; 1724 int dummy17; 1725 } 1726 1727 void dbus_signature_iter_init (DBusSignatureIter* iter, const(char)* signature); 1728 int dbus_signature_iter_get_current_type (const(DBusSignatureIter)* iter); 1729 char* dbus_signature_iter_get_signature (const(DBusSignatureIter)* iter); 1730 int dbus_signature_iter_get_element_type (const(DBusSignatureIter)* iter); 1731 dbus_bool_t dbus_signature_iter_next (DBusSignatureIter* iter); 1732 void dbus_signature_iter_recurse (const(DBusSignatureIter)* iter, DBusSignatureIter* subiter); 1733 dbus_bool_t dbus_signature_validate (const(char)* signature, DBusError* error); 1734 dbus_bool_t dbus_signature_validate_single (const(char)* signature, DBusError* error); 1735 dbus_bool_t dbus_type_is_valid (int typecode); 1736 dbus_bool_t dbus_type_is_basic (int typecode); 1737 dbus_bool_t dbus_type_is_container (int typecode); 1738 dbus_bool_t dbus_type_is_fixed (int typecode); 1739 // END dbus/dbus-signature.d 1740 // START dbus/dbus-misc.d 1741 char* dbus_get_local_machine_id (); 1742 void dbus_get_version (int* major_version_p, int* minor_version_p, int* micro_version_p); 1743 dbus_bool_t dbus_setenv (const(char)* variable, const(char)* value); 1744 // END dbus/dbus-misc.d 1745 // START dbus/dbus-threads.d 1746 alias DBusMutex* function () DBusMutexNewFunction; 1747 alias void function (DBusMutex*) DBusMutexFreeFunction; 1748 alias uint function (DBusMutex*) DBusMutexLockFunction; 1749 alias uint function (DBusMutex*) DBusMutexUnlockFunction; 1750 alias DBusMutex* function () DBusRecursiveMutexNewFunction; 1751 alias void function (DBusMutex*) DBusRecursiveMutexFreeFunction; 1752 alias void function (DBusMutex*) DBusRecursiveMutexLockFunction; 1753 alias void function (DBusMutex*) DBusRecursiveMutexUnlockFunction; 1754 alias DBusCondVar* function () DBusCondVarNewFunction; 1755 alias void function (DBusCondVar*) DBusCondVarFreeFunction; 1756 alias void function (DBusCondVar*, DBusMutex*) DBusCondVarWaitFunction; 1757 alias uint function (DBusCondVar*, DBusMutex*, int) DBusCondVarWaitTimeoutFunction; 1758 alias void function (DBusCondVar*) DBusCondVarWakeOneFunction; 1759 alias void function (DBusCondVar*) DBusCondVarWakeAllFunction; 1760 1761 1762 1763 enum DBusThreadFunctionsMask 1764 { 1765 DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK = 1, 1766 DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK = 2, 1767 DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK = 4, 1768 DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK = 8, 1769 DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK = 16, 1770 DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK = 32, 1771 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK = 64, 1772 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK = 128, 1773 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK = 256, 1774 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK = 512, 1775 DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK = 1024, 1776 DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK = 2048, 1777 DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK = 4096, 1778 DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK = 8192, 1779 DBUS_THREAD_FUNCTIONS_ALL_MASK = 16383 1780 } 1781 1782 struct DBusThreadFunctions 1783 { 1784 uint mask; 1785 DBusMutexNewFunction mutex_new; 1786 DBusMutexFreeFunction mutex_free; 1787 DBusMutexLockFunction mutex_lock; 1788 DBusMutexUnlockFunction mutex_unlock; 1789 DBusCondVarNewFunction condvar_new; 1790 DBusCondVarFreeFunction condvar_free; 1791 DBusCondVarWaitFunction condvar_wait; 1792 DBusCondVarWaitTimeoutFunction condvar_wait_timeout; 1793 DBusCondVarWakeOneFunction condvar_wake_one; 1794 DBusCondVarWakeAllFunction condvar_wake_all; 1795 DBusRecursiveMutexNewFunction recursive_mutex_new; 1796 DBusRecursiveMutexFreeFunction recursive_mutex_free; 1797 DBusRecursiveMutexLockFunction recursive_mutex_lock; 1798 DBusRecursiveMutexUnlockFunction recursive_mutex_unlock; 1799 void function () padding1; 1800 void function () padding2; 1801 void function () padding3; 1802 void function () padding4; 1803 } 1804 1805 struct DBusCondVar; 1806 1807 1808 struct DBusMutex; 1809 1810 1811 dbus_bool_t dbus_threads_init (const(DBusThreadFunctions)* functions); 1812 dbus_bool_t dbus_threads_init_default (); 1813 // END dbus/dbus-threads.d 1814 // START dbus/dbus-message.d 1815 struct DBusMessageIter 1816 { 1817 void* dummy1; 1818 void* dummy2; 1819 dbus_uint32_t dummy3; 1820 int dummy4; 1821 int dummy5; 1822 int dummy6; 1823 int dummy7; 1824 int dummy8; 1825 int dummy9; 1826 int dummy10; 1827 int dummy11; 1828 int pad1; 1829 int pad2; 1830 void* pad3; 1831 } 1832 1833 struct DBusMessage; 1834 1835 1836 DBusMessage* dbus_message_new (int message_type); 1837 DBusMessage* dbus_message_new_method_call (const(char)* bus_name, const(char)* path, const(char)* iface, const(char)* method); 1838 DBusMessage* dbus_message_new_method_return (DBusMessage* method_call); 1839 DBusMessage* dbus_message_new_signal (const(char)* path, const(char)* iface, const(char)* name); 1840 DBusMessage* dbus_message_new_error (DBusMessage* reply_to, const(char)* error_name, const(char)* error_message); 1841 DBusMessage* dbus_message_new_error_printf (DBusMessage* reply_to, const(char)* error_name, const(char)* error_format, ...); 1842 DBusMessage* dbus_message_copy (const(DBusMessage)* message); 1843 DBusMessage* dbus_message_ref (DBusMessage* message); 1844 void dbus_message_unref (DBusMessage* message); 1845 int dbus_message_get_type (DBusMessage* message); 1846 dbus_bool_t dbus_message_set_path (DBusMessage* message, const(char)* object_path); 1847 const(char)* dbus_message_get_path (DBusMessage* message); 1848 dbus_bool_t dbus_message_has_path (DBusMessage* message, const(char)* object_path); 1849 dbus_bool_t dbus_message_set_interface (DBusMessage* message, const(char)* iface); 1850 const(char)* dbus_message_get_interface (DBusMessage* message); 1851 dbus_bool_t dbus_message_has_interface (DBusMessage* message, const(char)* iface); 1852 dbus_bool_t dbus_message_set_member (DBusMessage* message, const(char)* member); 1853 const(char)* dbus_message_get_member (DBusMessage* message); 1854 dbus_bool_t dbus_message_has_member (DBusMessage* message, const(char)* member); 1855 dbus_bool_t dbus_message_set_error_name (DBusMessage* message, const(char)* name); 1856 const(char)* dbus_message_get_error_name (DBusMessage* message); 1857 dbus_bool_t dbus_message_set_destination (DBusMessage* message, const(char)* destination); 1858 const(char)* dbus_message_get_destination (DBusMessage* message); 1859 dbus_bool_t dbus_message_set_sender (DBusMessage* message, const(char)* sender); 1860 const(char)* dbus_message_get_sender (DBusMessage* message); 1861 const(char)* dbus_message_get_signature (DBusMessage* message); 1862 void dbus_message_set_no_reply (DBusMessage* message, dbus_bool_t no_reply); 1863 dbus_bool_t dbus_message_get_no_reply (DBusMessage* message); 1864 dbus_bool_t dbus_message_is_method_call (DBusMessage* message, const(char)* iface, const(char)* method); 1865 dbus_bool_t dbus_message_is_signal (DBusMessage* message, const(char)* iface, const(char)* signal_name); 1866 dbus_bool_t dbus_message_is_error (DBusMessage* message, const(char)* error_name); 1867 dbus_bool_t dbus_message_has_destination (DBusMessage* message, const(char)* bus_name); 1868 dbus_bool_t dbus_message_has_sender (DBusMessage* message, const(char)* unique_bus_name); 1869 dbus_bool_t dbus_message_has_signature (DBusMessage* message, const(char)* signature); 1870 dbus_uint32_t dbus_message_get_serial (DBusMessage* message); 1871 void dbus_message_set_serial (DBusMessage* message, dbus_uint32_t serial); 1872 dbus_bool_t dbus_message_set_reply_serial (DBusMessage* message, dbus_uint32_t reply_serial); 1873 dbus_uint32_t dbus_message_get_reply_serial (DBusMessage* message); 1874 void dbus_message_set_auto_start (DBusMessage* message, dbus_bool_t auto_start); 1875 dbus_bool_t dbus_message_get_auto_start (DBusMessage* message); 1876 dbus_bool_t dbus_message_get_path_decomposed (DBusMessage* message, char*** path); 1877 dbus_bool_t dbus_message_append_args (DBusMessage* message, int first_arg_type, ...); 1878 dbus_bool_t dbus_message_append_args_valist (DBusMessage* message, int first_arg_type, va_list var_args); 1879 dbus_bool_t dbus_message_get_args (DBusMessage* message, DBusError* error, int first_arg_type, ...); 1880 dbus_bool_t dbus_message_get_args_valist (DBusMessage* message, DBusError* error, int first_arg_type, va_list var_args); 1881 dbus_bool_t dbus_message_contains_unix_fds (DBusMessage* message); 1882 dbus_bool_t dbus_message_iter_init (DBusMessage* message, DBusMessageIter* iter); 1883 dbus_bool_t dbus_message_iter_has_next (DBusMessageIter* iter); 1884 dbus_bool_t dbus_message_iter_next (DBusMessageIter* iter); 1885 char* dbus_message_iter_get_signature (DBusMessageIter* iter); 1886 int dbus_message_iter_get_arg_type (DBusMessageIter* iter); 1887 int dbus_message_iter_get_element_type (DBusMessageIter* iter); 1888 void dbus_message_iter_recurse (DBusMessageIter* iter, DBusMessageIter* sub); 1889 void dbus_message_iter_get_basic (DBusMessageIter* iter, void* value); 1890 int dbus_message_iter_get_array_len (DBusMessageIter* iter); 1891 void dbus_message_iter_get_fixed_array (DBusMessageIter* iter, void* value, int* n_elements); 1892 void dbus_message_iter_init_append (DBusMessage* message, DBusMessageIter* iter); 1893 dbus_bool_t dbus_message_iter_append_basic (DBusMessageIter* iter, int type, const(void)* value); 1894 dbus_bool_t dbus_message_iter_append_fixed_array (DBusMessageIter* iter, int element_type, const(void)* value, int n_elements); 1895 dbus_bool_t dbus_message_iter_open_container (DBusMessageIter* iter, int type, const(char)* contained_signature, DBusMessageIter* sub); 1896 dbus_bool_t dbus_message_iter_close_container (DBusMessageIter* iter, DBusMessageIter* sub); 1897 void dbus_message_iter_abandon_container (DBusMessageIter* iter, DBusMessageIter* sub); 1898 void dbus_message_lock (DBusMessage* message); 1899 dbus_bool_t dbus_set_error_from_message (DBusError* error, DBusMessage* message); 1900 dbus_bool_t dbus_message_allocate_data_slot (dbus_int32_t* slot_p); 1901 void dbus_message_free_data_slot (dbus_int32_t* slot_p); 1902 dbus_bool_t dbus_message_set_data (DBusMessage* message, dbus_int32_t slot, void* data, DBusFreeFunction free_data_func); 1903 void* dbus_message_get_data (DBusMessage* message, dbus_int32_t slot); 1904 int dbus_message_type_from_string (const(char)* type_str); 1905 const(char)* dbus_message_type_to_string (int type); 1906 dbus_bool_t dbus_message_marshal (DBusMessage* msg, char** marshalled_data_p, int* len_p); 1907 DBusMessage* dbus_message_demarshal (const(char)* str, int len, DBusError* error); 1908 int dbus_message_demarshal_bytes_needed (const(char)* str, int len); 1909 // END dbus/dbus-message.d 1910 // START dbus/dbus-connection.d 1911 alias uint function (DBusWatch*, void*) DBusAddWatchFunction; 1912 alias void function (DBusWatch*, void*) DBusWatchToggledFunction; 1913 alias void function (DBusWatch*, void*) DBusRemoveWatchFunction; 1914 alias uint function (DBusTimeout*, void*) DBusAddTimeoutFunction; 1915 alias void function (DBusTimeout*, void*) DBusTimeoutToggledFunction; 1916 alias void function (DBusTimeout*, void*) DBusRemoveTimeoutFunction; 1917 alias void function (DBusConnection*, DBusDispatchStatus, void*) DBusDispatchStatusFunction; 1918 alias void function (void*) DBusWakeupMainFunction; 1919 alias uint function (DBusConnection*, c_ulong, void*) DBusAllowUnixUserFunction; 1920 alias uint function (DBusConnection*, const(char)*, void*) DBusAllowWindowsUserFunction; 1921 alias void function (DBusPendingCall*, void*) DBusPendingCallNotifyFunction; 1922 alias DBusHandlerResult function (DBusConnection*, DBusMessage*, void*) DBusHandleMessageFunction; 1923 alias void function (DBusConnection*, void*) DBusObjectPathUnregisterFunction; 1924 alias DBusHandlerResult function (DBusConnection*, DBusMessage*, void*) DBusObjectPathMessageFunction; 1925 1926 enum DBusWatchFlags 1927 { 1928 DBUS_WATCH_READABLE = 1, 1929 DBUS_WATCH_WRITABLE = 2, 1930 DBUS_WATCH_ERROR = 4, 1931 DBUS_WATCH_HANGUP = 8 1932 } 1933 1934 enum DBusDispatchStatus 1935 { 1936 DBUS_DISPATCH_DATA_REMAINS = 0, 1937 DBUS_DISPATCH_COMPLETE = 1, 1938 DBUS_DISPATCH_NEED_MEMORY = 2 1939 } 1940 1941 struct DBusObjectPathVTable 1942 { 1943 DBusObjectPathUnregisterFunction unregister_function; 1944 DBusObjectPathMessageFunction message_function; 1945 void function (void*) dbus_internal_pad1; 1946 void function (void*) dbus_internal_pad2; 1947 void function (void*) dbus_internal_pad3; 1948 void function (void*) dbus_internal_pad4; 1949 } 1950 1951 struct DBusPreallocatedSend; 1952 1953 1954 struct DBusTimeout; 1955 1956 1957 struct DBusPendingCall; 1958 1959 1960 struct DBusConnection; 1961 1962 1963 struct DBusWatch; 1964 1965 1966 DBusConnection* dbus_connection_open (const(char)* address, DBusError* error); 1967 DBusConnection* dbus_connection_open_private (const(char)* address, DBusError* error); 1968 DBusConnection* dbus_connection_ref (DBusConnection* connection); 1969 void dbus_connection_unref (DBusConnection* connection); 1970 void dbus_connection_close (DBusConnection* connection); 1971 dbus_bool_t dbus_connection_get_is_connected (DBusConnection* connection); 1972 dbus_bool_t dbus_connection_get_is_authenticated (DBusConnection* connection); 1973 dbus_bool_t dbus_connection_get_is_anonymous (DBusConnection* connection); 1974 char* dbus_connection_get_server_id (DBusConnection* connection); 1975 dbus_bool_t dbus_connection_can_send_type (DBusConnection* connection, int type); 1976 void dbus_connection_set_exit_on_disconnect (DBusConnection* connection, dbus_bool_t exit_on_disconnect); 1977 void dbus_connection_flush (DBusConnection* connection); 1978 dbus_bool_t dbus_connection_read_write_dispatch (DBusConnection* connection, int timeout_milliseconds); 1979 dbus_bool_t dbus_connection_read_write (DBusConnection* connection, int timeout_milliseconds); 1980 DBusMessage* dbus_connection_borrow_message (DBusConnection* connection); 1981 void dbus_connection_return_message (DBusConnection* connection, DBusMessage* message); 1982 void dbus_connection_steal_borrowed_message (DBusConnection* connection, DBusMessage* message); 1983 DBusMessage* dbus_connection_pop_message (DBusConnection* connection); 1984 DBusDispatchStatus dbus_connection_get_dispatch_status (DBusConnection* connection); 1985 DBusDispatchStatus dbus_connection_dispatch (DBusConnection* connection); 1986 dbus_bool_t dbus_connection_has_messages_to_send (DBusConnection* connection); 1987 dbus_bool_t dbus_connection_send (DBusConnection* connection, DBusMessage* message, dbus_uint32_t* client_serial); 1988 dbus_bool_t dbus_connection_send_with_reply (DBusConnection* connection, DBusMessage* message, DBusPendingCall** pending_return, int timeout_milliseconds); 1989 DBusMessage* dbus_connection_send_with_reply_and_block (DBusConnection* connection, DBusMessage* message, int timeout_milliseconds, DBusError* error); 1990 dbus_bool_t dbus_connection_set_watch_functions (DBusConnection* connection, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void* data, DBusFreeFunction free_data_function); 1991 dbus_bool_t dbus_connection_set_timeout_functions (DBusConnection* connection, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, DBusTimeoutToggledFunction toggled_function, void* data, DBusFreeFunction free_data_function); 1992 void dbus_connection_set_wakeup_main_function (DBusConnection* connection, DBusWakeupMainFunction wakeup_main_function, void* data, DBusFreeFunction free_data_function); 1993 void dbus_connection_set_dispatch_status_function (DBusConnection* connection, DBusDispatchStatusFunction function_, void* data, DBusFreeFunction free_data_function); 1994 dbus_bool_t dbus_connection_get_unix_user (DBusConnection* connection, c_ulong* uid); 1995 dbus_bool_t dbus_connection_get_unix_process_id (DBusConnection* connection, c_ulong* pid); 1996 dbus_bool_t dbus_connection_get_adt_audit_session_data (DBusConnection* connection, void** data, dbus_int32_t* data_size); 1997 void dbus_connection_set_unix_user_function (DBusConnection* connection, DBusAllowUnixUserFunction function_, void* data, DBusFreeFunction free_data_function); 1998 dbus_bool_t dbus_connection_get_windows_user (DBusConnection* connection, char** windows_sid_p); 1999 void dbus_connection_set_windows_user_function (DBusConnection* connection, DBusAllowWindowsUserFunction function_, void* data, DBusFreeFunction free_data_function); 2000 void dbus_connection_set_allow_anonymous (DBusConnection* connection, dbus_bool_t value); 2001 void dbus_connection_set_route_peer_messages (DBusConnection* connection, dbus_bool_t value); 2002 dbus_bool_t dbus_connection_add_filter (DBusConnection* connection, DBusHandleMessageFunction function_, void* user_data, DBusFreeFunction free_data_function); 2003 void dbus_connection_remove_filter (DBusConnection* connection, DBusHandleMessageFunction function_, void* user_data); 2004 dbus_bool_t dbus_connection_allocate_data_slot (dbus_int32_t* slot_p); 2005 void dbus_connection_free_data_slot (dbus_int32_t* slot_p); 2006 dbus_bool_t dbus_connection_set_data (DBusConnection* connection, dbus_int32_t slot, void* data, DBusFreeFunction free_data_func); 2007 void* dbus_connection_get_data (DBusConnection* connection, dbus_int32_t slot); 2008 void dbus_connection_set_change_sigpipe (dbus_bool_t will_modify_sigpipe); 2009 void dbus_connection_set_max_message_size (DBusConnection* connection, c_long size); 2010 c_long dbus_connection_get_max_message_size (DBusConnection* connection); 2011 void dbus_connection_set_max_received_size (DBusConnection* connection, c_long size); 2012 c_long dbus_connection_get_max_received_size (DBusConnection* connection); 2013 void dbus_connection_set_max_message_unix_fds (DBusConnection* connection, c_long n); 2014 c_long dbus_connection_get_max_message_unix_fds (DBusConnection* connection); 2015 void dbus_connection_set_max_received_unix_fds (DBusConnection* connection, c_long n); 2016 c_long dbus_connection_get_max_received_unix_fds (DBusConnection* connection); 2017 c_long dbus_connection_get_outgoing_size (DBusConnection* connection); 2018 c_long dbus_connection_get_outgoing_unix_fds (DBusConnection* connection); 2019 DBusPreallocatedSend* dbus_connection_preallocate_send (DBusConnection* connection); 2020 void dbus_connection_free_preallocated_send (DBusConnection* connection, DBusPreallocatedSend* preallocated); 2021 void dbus_connection_send_preallocated (DBusConnection* connection, DBusPreallocatedSend* preallocated, DBusMessage* message, dbus_uint32_t* client_serial); 2022 dbus_bool_t dbus_connection_try_register_object_path (DBusConnection* connection, const(char)* path, const(DBusObjectPathVTable)* vtable, void* user_data, DBusError* error); 2023 dbus_bool_t dbus_connection_register_object_path (DBusConnection* connection, const(char)* path, const(DBusObjectPathVTable)* vtable, void* user_data); 2024 dbus_bool_t dbus_connection_try_register_fallback (DBusConnection* connection, const(char)* path, const(DBusObjectPathVTable)* vtable, void* user_data, DBusError* error); 2025 dbus_bool_t dbus_connection_register_fallback (DBusConnection* connection, const(char)* path, const(DBusObjectPathVTable)* vtable, void* user_data); 2026 dbus_bool_t dbus_connection_unregister_object_path (DBusConnection* connection, const(char)* path); 2027 dbus_bool_t dbus_connection_get_object_path_data (DBusConnection* connection, const(char)* path, void** data_p); 2028 dbus_bool_t dbus_connection_list_registered (DBusConnection* connection, const(char)* parent_path, char*** child_entries); 2029 dbus_bool_t dbus_connection_get_unix_fd (DBusConnection* connection, int* fd); 2030 dbus_bool_t dbus_connection_get_socket (DBusConnection* connection, int* fd); 2031 int dbus_watch_get_fd (DBusWatch* watch); 2032 int dbus_watch_get_unix_fd (DBusWatch* watch); 2033 int dbus_watch_get_socket (DBusWatch* watch); 2034 uint dbus_watch_get_flags (DBusWatch* watch); 2035 void* dbus_watch_get_data (DBusWatch* watch); 2036 void dbus_watch_set_data (DBusWatch* watch, void* data, DBusFreeFunction free_data_function); 2037 dbus_bool_t dbus_watch_handle (DBusWatch* watch, uint flags); 2038 dbus_bool_t dbus_watch_get_enabled (DBusWatch* watch); 2039 int dbus_timeout_get_interval (DBusTimeout* timeout); 2040 void* dbus_timeout_get_data (DBusTimeout* timeout); 2041 void dbus_timeout_set_data (DBusTimeout* timeout, void* data, DBusFreeFunction free_data_function); 2042 dbus_bool_t dbus_timeout_handle (DBusTimeout* timeout); 2043 dbus_bool_t dbus_timeout_get_enabled (DBusTimeout* timeout); 2044 // END dbus/dbus-connection.d 2045 // START dbus/dbus-pending-call.d 2046 DBusPendingCall* dbus_pending_call_ref (DBusPendingCall* pending); 2047 void dbus_pending_call_unref (DBusPendingCall* pending); 2048 dbus_bool_t dbus_pending_call_set_notify (DBusPendingCall* pending, DBusPendingCallNotifyFunction function_, void* user_data, DBusFreeFunction free_user_data); 2049 void dbus_pending_call_cancel (DBusPendingCall* pending); 2050 dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall* pending); 2051 DBusMessage* dbus_pending_call_steal_reply (DBusPendingCall* pending); 2052 void dbus_pending_call_block (DBusPendingCall* pending); 2053 dbus_bool_t dbus_pending_call_allocate_data_slot (dbus_int32_t* slot_p); 2054 void dbus_pending_call_free_data_slot (dbus_int32_t* slot_p); 2055 dbus_bool_t dbus_pending_call_set_data (DBusPendingCall* pending, dbus_int32_t slot, void* data, DBusFreeFunction free_data_func); 2056 void* dbus_pending_call_get_data (DBusPendingCall* pending, dbus_int32_t slot); 2057 // END dbus/dbus-pending-call.d 2058 // START dbus/dbus-server.d 2059 alias void function (DBusServer*, DBusConnection*, void*) DBusNewConnectionFunction; 2060 2061 struct DBusServer; 2062 2063 2064 DBusServer* dbus_server_listen (const(char)* address, DBusError* error); 2065 DBusServer* dbus_server_ref (DBusServer* server); 2066 void dbus_server_unref (DBusServer* server); 2067 void dbus_server_disconnect (DBusServer* server); 2068 dbus_bool_t dbus_server_get_is_connected (DBusServer* server); 2069 char* dbus_server_get_address (DBusServer* server); 2070 char* dbus_server_get_id (DBusServer* server); 2071 void dbus_server_set_new_connection_function (DBusServer* server, DBusNewConnectionFunction function_, void* data, DBusFreeFunction free_data_function); 2072 dbus_bool_t dbus_server_set_watch_functions (DBusServer* server, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void* data, DBusFreeFunction free_data_function); 2073 dbus_bool_t dbus_server_set_timeout_functions (DBusServer* server, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, DBusTimeoutToggledFunction toggled_function, void* data, DBusFreeFunction free_data_function); 2074 dbus_bool_t dbus_server_set_auth_mechanisms (DBusServer* server, const(char*)* mechanisms); 2075 dbus_bool_t dbus_server_allocate_data_slot (dbus_int32_t* slot_p); 2076 void dbus_server_free_data_slot (dbus_int32_t* slot_p); 2077 dbus_bool_t dbus_server_set_data (DBusServer* server, int slot, void* data, DBusFreeFunction free_data_func); 2078 void* dbus_server_get_data (DBusServer* server, int slot); 2079 // END dbus/dbus-server.d 2080 // START dbus/dbus-bus.d 2081 DBusConnection* dbus_bus_get (DBusBusType type, DBusError* error); 2082 DBusConnection* dbus_bus_get_private (DBusBusType type, DBusError* error); 2083 dbus_bool_t dbus_bus_register (DBusConnection* connection, DBusError* error); 2084 dbus_bool_t dbus_bus_set_unique_name (DBusConnection* connection, const(char)* unique_name); 2085 const(char)* dbus_bus_get_unique_name (DBusConnection* connection); 2086 c_ulong dbus_bus_get_unix_user (DBusConnection* connection, const(char)* name, DBusError* error); 2087 char* dbus_bus_get_id (DBusConnection* connection, DBusError* error); 2088 int dbus_bus_request_name (DBusConnection* connection, const(char)* name, uint flags, DBusError* error); 2089 int dbus_bus_release_name (DBusConnection* connection, const(char)* name, DBusError* error); 2090 dbus_bool_t dbus_bus_name_has_owner (DBusConnection* connection, const(char)* name, DBusError* error); 2091 dbus_bool_t dbus_bus_start_service_by_name (DBusConnection* connection, const(char)* name, dbus_uint32_t flags, dbus_uint32_t* reply, DBusError* error); 2092 void dbus_bus_add_match (DBusConnection* connection, const(char)* rule, DBusError* error); 2093 void dbus_bus_remove_match (DBusConnection* connection, const(char)* rule, DBusError* error); 2094 // END dbus/dbus-bus.d 2095 // START dbus/dbus.d 2096 2097 // END dbus/dbus.d 2098 } 2099 2100 2101 enum BusService = "org.freedesktop.DBus"; 2102 enum BusPath = "/org/freedesktop/DBus"; 2103 enum BusInterface = "org.freedesktop.DBus"; 2104 2105 enum NameFlags { 2106 AllowReplace = 1, ReplaceExisting = 2, NoQueue = 4 2107 } 2108 2109 /// Requests a DBus well-known name. 2110 /// returns if the name is owned after the call. 2111 /// Involves blocking call on a DBus method, may throw an exception on failure. 2112 bool requestName(Connection conn, string name, 2113 NameFlags flags = NameFlags.NoQueue | NameFlags.AllowReplace) { 2114 auto msg = Message(BusService,BusPath,BusInterface,"RequestName"); 2115 msg.build(name,cast(uint)(flags)); 2116 auto res = conn.sendWithReplyBlocking(msg).to!uint; 2117 return (res == 1) || (res == 4); 2118 } 2119 2120 /// A simple main loop that isn't necessarily efficient 2121 /// and isn't guaranteed to work with other tasks and threads. 2122 /// Use only for apps that only do DBus triggered things. 2123 void simpleMainLoop(Connection conn) { 2124 while(dbus_connection_read_write_dispatch(conn.conn, -1)) {} // empty loop body 2125 } 2126 2127 /// Single tick in the DBus connection which can be used for 2128 /// concurrent updates. 2129 bool tick(Connection conn) { 2130 return cast(bool) dbus_connection_read_write_dispatch(conn.conn, 0); 2131 } 2132 2133