Tcl DBus Interface

Check-in [d409275cf0]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:With version 3.0 of the dbus library, the module doesn't need to handle multiple interps on the same connection anymore. This removes an argument from some commands. For that reason the major version number has been incremented.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | master
Files: files | file ages | folders
SHA3-256:d409275cf0c67b6730c3fb25e60857829b28655f70ebdb42017fad4227bfefd3
User & Date: schelte 2019-01-12 16:09:03
Context
2019-01-12
16:18
Forgot to adjust the version numbers in the manual page Leaf check-in: 83048b4057 user: schelte tags: trunk, master
16:09
With version 3.0 of the dbus library, the module doesn't need to handle multiple interps on the same connection anymore. This removes an argument from some commands. For that reason the major version number has been incremented. check-in: d409275cf0 user: schelte tags: trunk, master
2018-09-28
09:47
Add missed dbus version number to the manual page. check-in: 6da4a0f17a user: schelte tags: trunk, master, release-1-4
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.

60
61
62
63
64
65
66







	  underlying nodes from being discovered via introspection.
	- Deleting a node should also delete any child nodes.
	- Fix error when a method deletes its own path.
	- The generate command doesn't always correctly determine whether the
	  result of the signal body should be interpreted as a single value or
	  a list.
	- Properly handle complex signatures for properties.














>
>
>
>
>
>
>
60
61
62
63
64
65
66
67
68
69
70
71
72
73
	  underlying nodes from being discovered via introspection.
	- Deleting a node should also delete any child nodes.
	- Fix error when a method deletes its own path.
	- The generate command doesn't always correctly determine whether the
	  result of the signal body should be interpreted as a single value or
	  a list.
	- Properly handle complex signatures for properties.

Version 1.4 - Sep 28 2018
	- Make the module compatible with version 3.0 of the dbus library.

Version 2.0 - Jan 12 2019
	- With version 3.0 of the dbus library, the module doesn't need to
	  handle multiple interps on the same connection anymore.

Changes to configure.

1
2
3
4
5
6
7
8
9
10
...
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
....
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
....
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
....
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
....
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
....
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
....
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for dbif 1.4.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
................................................................................
subdirs=
MFLAGS=
MAKEFLAGS=

# Identity of this package.
PACKAGE_NAME='dbif'
PACKAGE_TARNAME='dbif'
PACKAGE_VERSION='1.4'
PACKAGE_STRING='dbif 1.4'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''

ac_subst_vars='LTLIBOBJS
LIBOBJS
INSTALLDOC
DTPLITE_PROG
................................................................................
#
# Report the --help message.
#
if test "$ac_init_help" = "long"; then
  # Omit some internal or obsolete options to make the list less imposing.
  # This message is too long to be a string in the A/UX 3.1 sh.
  cat <<_ACEOF
\`configure' configures dbif 1.4 to adapt to many kinds of systems.

Usage: $0 [OPTION]... [VAR=VALUE]...

To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.

Defaults for the options are specified in brackets.
................................................................................

  cat <<\_ACEOF
_ACEOF
fi

if test -n "$ac_init_help"; then
  case $ac_init_help in
     short | recursive ) echo "Configuration of dbif 1.4:";;
   esac
  cat <<\_ACEOF

Optional Packages:
  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
  --with-tcl              directory containing tcl configuration
................................................................................
    cd "$ac_pwd" || { ac_status=$?; break; }
  done
fi

test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
  cat <<\_ACEOF
dbif configure 1.4
generated by GNU Autoconf 2.69

Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
  exit
................................................................................
  as_fn_set_status $ac_retval

} # ac_fn_c_try_compile
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.

It was created by dbif $as_me 1.4, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  $ $0 $@

_ACEOF
exec 5>>config.log
{
................................................................................
test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# Save the log message, to keep $0 and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by dbif $as_me 1.4, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  CONFIG_FILES    = $CONFIG_FILES
  CONFIG_HEADERS  = $CONFIG_HEADERS
  CONFIG_LINKS    = $CONFIG_LINKS
  CONFIG_COMMANDS = $CONFIG_COMMANDS
  $ $0 $@
................................................................................

Report bugs to the package provider."

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
dbif config.status 1.4
configured by $0, generated by GNU Autoconf 2.69,
  with options \\"\$ac_cs_config\\"

Copyright (C) 2012 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."



|







 







|
|







 







|







 







|







 







|







 







|







 







|







 







|







1
2
3
4
5
6
7
8
9
10
...
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
....
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
....
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
....
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
....
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
....
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
....
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for dbif 2.0.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
................................................................................
subdirs=
MFLAGS=
MAKEFLAGS=

# Identity of this package.
PACKAGE_NAME='dbif'
PACKAGE_TARNAME='dbif'
PACKAGE_VERSION='2.0'
PACKAGE_STRING='dbif 2.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''

ac_subst_vars='LTLIBOBJS
LIBOBJS
INSTALLDOC
DTPLITE_PROG
................................................................................
#
# Report the --help message.
#
if test "$ac_init_help" = "long"; then
  # Omit some internal or obsolete options to make the list less imposing.
  # This message is too long to be a string in the A/UX 3.1 sh.
  cat <<_ACEOF
\`configure' configures dbif 2.0 to adapt to many kinds of systems.

Usage: $0 [OPTION]... [VAR=VALUE]...

To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.

Defaults for the options are specified in brackets.
................................................................................

  cat <<\_ACEOF
_ACEOF
fi

if test -n "$ac_init_help"; then
  case $ac_init_help in
     short | recursive ) echo "Configuration of dbif 2.0:";;
   esac
  cat <<\_ACEOF

Optional Packages:
  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
  --with-tcl              directory containing tcl configuration
................................................................................
    cd "$ac_pwd" || { ac_status=$?; break; }
  done
fi

test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
  cat <<\_ACEOF
dbif configure 2.0
generated by GNU Autoconf 2.69

Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
  exit
................................................................................
  as_fn_set_status $ac_retval

} # ac_fn_c_try_compile
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.

It was created by dbif $as_me 2.0, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  $ $0 $@

_ACEOF
exec 5>>config.log
{
................................................................................
test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# Save the log message, to keep $0 and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by dbif $as_me 2.0, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  CONFIG_FILES    = $CONFIG_FILES
  CONFIG_HEADERS  = $CONFIG_HEADERS
  CONFIG_LINKS    = $CONFIG_LINKS
  CONFIG_COMMANDS = $CONFIG_COMMANDS
  $ $0 $@
................................................................................

Report bugs to the package provider."

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
dbif config.status 2.0
configured by $0, generated by GNU Autoconf 2.69,
  with options \\"\$ac_cs_config\\"

Copyright (C) 2012 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."

Changes to configure.ac.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION
# set as provided.  These will also be added as -D defs in your Makefile
# so you can encode the package version directly into the source files.
# This will also define a special symbol for Windows (BUILD_<PACKAGE_NAME>
# so that we create the export library with the dll.
#-----------------------------------------------------------------------

AC_INIT([dbif], [1.4])

#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
# This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
#--------------------------------------------------------------------








|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION
# set as provided.  These will also be added as -D defs in your Makefile
# so you can encode the package version directly into the source files.
# This will also define a special symbol for Windows (BUILD_<PACKAGE_NAME>
# so that we create the export library with the dll.
#-----------------------------------------------------------------------

AC_INIT([dbif], [2.0])

#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
# This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
#--------------------------------------------------------------------

Changes to dbif.tcl.

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
..
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
...
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
...
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
...
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
...
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
...
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
...
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
...
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
...
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
...
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
...
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
...
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
...
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
....
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013

1014
1015
1016

1017
1018
1019
1020
1021
1022
1023
....
1068
1069
1070
1071
1072
1073
1074

1075
1076
1077
1078
1079
1080
1081
1082
1083
....
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
....
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
# provide a number of standard DBus interfaces in a Tcl application.
#
# The following interfaces are supported:
#	org.freedesktop.DBus.Peer
#	org.freedesktop.DBus.Introspectable
#	org.freedesktop.DBus.Properties

package require dbus 2.1 3.0
package provide dbif 1.4
package provide dbus-intf 1.4

namespace eval dbus::dbif {
    # Setup some defaults in case the user doesn't specify certain options
    variable defaults [dict create bus session intf com.tclcode.default]

    # Mapping of bus names to dbus handles
    variable handle {}
................................................................................
    set signal(PropertiesChanged) {
	dbus ""
	path ""
	interface org.freedesktop.DBus.Properties
	name PropertiesChanged
	signature sa{sv}as
	command ::dbus::dbif::propchanged
	interp {}
	meta {}
	args {
	    interface_name s
	    changed_properties a{sv}
	    invalidated_properties as
	}
    }
................................................................................
    }
    return [dict create signature $signature args $args]
}

# Define a method that can be called over the DBus
#
proc dbus::dbif::define \
  {dbus path intf name cmd int {in {}} {out {}} {meta {}} {async 0}} {
    variable dbif
    create $dbus $path $intf
    set args [args $in]
    dict update args signature sig args inargs {}
    set args [args $out]
    dict update args signature ret args outargs {}
    set dict [dict create command $cmd interp $int signature $ret \
      in $inargs out $outargs meta $meta async $async]
    dict set dbif($dbus|$path|$intf) methods $name,$sig $dict
}

proc dbus::dbif::undefine {dbus path intf name cmd int {in {}}} {
    variable dbif
    if {![info exists dbif($dbus|$path|$intf)]} return
    set args [args $in]
    dict update args signature sig args inargs {}
    dict unset dbif($dbus|$path|$intf) methods $name,$sig
}

................................................................................
	}
	set arglist [lassign $arglist var]
    }
}

# Get the namespace of the caller
#
proc dbus::dbif::getns {interp} {
    if {$interp eq ""} {
	# This is a helper procedure. So 1 level up is the actual procedure
	# We need to go 2 levels up for the caller of the actual procedure
	return [uplevel 2 [list namespace current]]
    } else {
	# If the command is in another interpreter, we probably arived here
	# through an interp alias. In that case the calling context of that
	# interp is accessible via interp eval
	return [interp eval $interp [list namespace current]]
    }
}

# Access the miscellaneous information of a message
#
proc dbus::dbif::get {id name} {
    variable info
    if {![info exists info($id)]} {
................................................................................
	    if {!$trace} return
	    if {$access ni {read readwrite}} return
	    if {$ecs ni {true invalidates}} return
	}
	set inv [expr {$ecs eq "invalidates"}]
	set trc [list dbus::dbif::propchg $dbus $path $intf $name $inv]
	set cmd [list trace $op variable $variable {write unset} $trc]
	interp eval $interp [list uplevel #0 $cmd]
    }
    return
}

# Needs to be exposed via the regular API?
proc dbus::dbif::changedsignal {state} {
    variable trace
................................................................................

# Define a signal that the application may send
#
proc dbus::dbif::signal {args} {
    variable defaults; variable dbif; variable signal; variable sigid
    dict with defaults {}; set meta {}
    set id ""
    cmdline opt arg {path name {in {}} {opt {}} {arglist {}} {body {}}} $args {
	-id: {set id $arg}
	-bus: {set bus [buscheck $arg]}
	-interface: {set intf [intfcheck $arg]}
	-attributes: {set meta [metacheck $arg]}
    }
    set dbus [handle $bus]
    if {$body eq ""} {
	set body $arglist
	set arglist $opt
	set interp ""
    } else {
	set interp $opt
    }
    if {$name ne ""} {
	namecheck $name
	# Signals without a predefined path need a body to provide the path
	if {$path ne "" || $body eq ""} {pathcheck $path}
	create $dbus $path $intf
	if {$id eq ""} {set id signal[incr sigid]}
	set dict [dict create dbus $dbus path $path \
	  interface $intf name $name command "" interp $interp]
	if {$body ne ""} {
	    set ns [getns $interp]
	    dict set dict command [list apply [list $arglist $body $ns]]
	}
    }
    if {[info exists signal($id)]} {
	# Clean up the old signal
	dict update signal($id) dbus obus path opath interface ointf {}
	if {$obus eq ""} {
................................................................................
}

# Define a property that may be accessed through the DBus
#
proc dbus::dbif::property {args} {
    variable defaults; variable dbif
    dict with defaults {}; set op readwrite; set meta {}
    cmdline opt arg {path name var args} $args {
	-bus: {set bus [buscheck $arg]}
	-interface: {set intf [intfcheck $arg]}
	-access: {set op [accesscheck $arg]}
	-attributes: {set meta [metacheck $arg]}
    }
    set dbus [handle $bus]
    if {[llength $args] <= 2} {
	lassign [lreverse $args] body interp
    } else {
	set cmd {dbif property ?options? path name var ?interp ?body??}
	error [format {wrong # args: should be "%s"} $cmd]
    }
    set args [args [list $name] Property]
    set name [lindex [dict get $args args] 0]
    set sig [lindex [dict get $args signature] 0]
    # Properties should be a single complete type, otherwise
    # GetAll will produce invalid results
    set cnt [argcount [list $name $sig]]
    if {$cnt != 1} {
................................................................................

    if {$var eq {}} {
	dict unset $dbif($dbus|$path|$intf) properties $name
	return
    }
	
    if {$body ne ""} {
	set ns [getns $interp]
	set cmd [list apply [list [list msgid $name] $body $ns]]
    } else {
	set cmd ""
    }
    set dict [dict create variable $var access $op signature $sig \
      command $cmd interp $interp meta $meta]
    dict set dbif($dbus|$path|$intf) properties $name $dict

    # Setup a variable trace for readable properties
    vartrace add $dbus $path $intf $name
    if {$interp ne {}} {
	interp alias $interp ::dbus::dbif::propchg {} ::dbus::dbif::propchg
    }
}

# Define how to handle a method call
#
proc dbus::dbif::method {args} {
    variable defaults
    dict with defaults {}; set meta {}; set async 0; set opts {}
    cmdline opt arg {path cmd {in ""} {out ""} {interp ""} body} $args {
        -bus: {set bus [buscheck $arg]}
        -interface: {set intf [intfcheck $arg]}
	-attributes: {set meta [metacheck $arg]}
	-async {set async 1}
	-details {lappend opts -details}
    }
    set dbus [handle $bus]
................................................................................
	    lassign [split $n :] name sig
	    lappend args $name
	    lset info 0 [linsert [lindex $info 0] end $n]
	}
    }
    if {$body eq {}} {
	foreach n $info {
	    undefine $dbus $path $intf $cmd $interp $n
	}
    } else {
	set ns [getns $interp]
	set code [list apply [list [linsert $args 0 msgid] $body $ns]]
	foreach n $info {
	    define $dbus $path $intf $cmd $code $interp $n $out $meta $async
	}
	dbus method $dbus {*}$opts \
	  $path $intf.$cmd [list dbus::dbif::methods $dbus]
    }
}

# Generate a signal according to an earlier specification
................................................................................
#
proc dbus::dbif::generate {id args} {
    variable signal
    if {![info exists signal($id)]} {
	error "Signal '$id' has not been defined"
    }
    set cmd [dict get $signal($id) command]
    set int [dict get $signal($id) interp]
    if {$cmd eq ""} {
    	set argv $args
	dict with signal($id) {}
    } else {
	# Need to use catch to get the additional return options
	if {[catch {interp eval $int [list uplevel #0 $cmd $args]} argv opts]} {
	    # Rethrow any exceptions
	    return -options $opts $argv
	}
	dict with signal($id) {}
	if {$path eq ""} {
	    # Standard signal, body code must have provided the path
	    if {[dict exists $opts -path]} {
................................................................................
}

# Setup a signal handler for a specific signal
#
proc dbus::dbif::listen {args} {
    variable defaults; variable hear
    dict with defaults {}
    cmdline opt arg {path name {arglist ""} {interp ""} body} $args {
        -bus: {set bus [buscheck $arg]}
        -interface: {set intf [intfcheck $arg]}
    }
    set dbus [handle $bus]
    dbus filter $dbus add \
      -type signal -path $path -interface $intf -member $name
    set args {}
................................................................................
	} else {
	    lassign [split $n :] var sig
	    if {$sig eq ""} {set sig s}
	    lappend args $var
	    lset info 0 [lindex $info 0]$sig
	}
    }
    set ns [getns $interp]
    set code [list apply [list [linsert $args 0 msgid] $body $ns]]
    foreach n $info {
    	set dict [dict create command $code interp $interp]
    	dict set hear($dbus,$path,$intf) $name,$n $dict
    }
    dbus listen $dbus $path $intf.$name [list dbus::dbif::signals $dbus]
}

# Send a response to a DBus message
#
................................................................................
	    dbuserr signature $dbus $path $intf $name $sig $signature
    	}
	if {$command ne ""} {
	    set id message[incr msgid]
	    set afterid [after $timeout [list dbus::dbif::expire $id]]
	    set info($id) \
	      [dict merge $data [dict create bus $dbus afterid $afterid]]
	    if {[catch {interp eval $interp \
	      [list uplevel #0 [linsert $command end $id $arg]]} res opts]} {
		expire $id
		# Rethrow the error so it gets reported back to the caller
		return -options [dict incr opts -level] $res
	    }
	    expire $id
	}
	interp eval $interp [list uplevel #0 [list set $variable $arg]]
    }
    dict with data {
    	dbus return $dbus $sender $serial
    }
    return -async 1
}

................................................................................
	dbuserr interface $dbus $path $intf
    }
    if {![dict exists $dbif($dbus|$path|$intf) properties $name]} {
	dbuserr property $dbus $path $intf $name
    }
    set op [dict get $dbif($dbus|$path|$intf) properties $name access]
    if {$op ni {read readwrite}} {dbuserr access $dbus $path $intf $name read}
    set interp [dict get $dbif($dbus|$path|$intf) properties $name interp]
    set var [dict get $dbif($dbus|$path|$intf) properties $name variable]
    if {[interp eval $interp [list uplevel #0 [list info exists $var]]]} {
	set sig [dict get $dbif($dbus|$path|$intf) properties $name signature]
	set dest [dict get $data sender]
	set serial [dict get $data serial]
	set value [interp eval $interp [list uplevel #0 [list set $var]]]
	dbus return $dbus -signature $sig $dest $serial $value
    } else {
	dbuserr propunset $dbus $path $intf $name
    }
    return -async 1
}

................................................................................
    set path [dict get $data path]
    if {![info exists dbif($dbus|$path|$intf)]} {
	dbuserr interface $dbus $path $intf
    }
    if {![dict exists $dbif($dbus|$path|$intf) properties]} {return {}}
    set rc {}
    dict for {n v} [dict get $dbif($dbus|$path|$intf) properties] {
	set interp [dict get $v interp]
	set var [dict get $v variable]
	if {[interp eval $interp [list uplevel #0 [list info exists $var]]]} {
	    set sig [dict get $v signature]
	    set value [interp eval $interp [list uplevel #0 [list set $var]]]
	    lappend rc $n [list $sig $value]
	}
    }
    dict with data {
 	dbus return $dbus -signature a{sv} $sender $serial $rc
    }
    return -async 1
................................................................................
    variable dbif
    set change {}
    set invalid {}
    dict for {key op} [dict get $propchg $dbus $path $intf] {
	if {$op eq "write"} {
	    set info [dict get $dbif($dbus|$path|$intf) properties $key]
	    dict with info {}
	    set value [interp eval $interp \
	      [list uplevel #0 [list set $variable]]]
	    dict set change $key [list $signature $value]
	} else {
	    lappend invalid $key
	}
    }
    dict unset propchg $dbus $path $intf
    variable signal
................................................................................
		    # Report values that do not match the signature
		    if {[catch {generate PropertiesChanged \
		      $path $intf $dbus} msg opts]} {
			set str "failed to generate the PropertiesChanged\
			  dbus signal for interface '$intf' on path '$path'.\
			  Reason: $msg"
			dict set opts -errorinfo $str
			# Get the error reporting command for the interp
			set errcmd [interp bgerror {}]
			# Report the error without throwing an exception
			catch {{*}$errcmd $str $opts}
		    }
		}
	    }
	}
................................................................................
			if {![dict exists $init node {} interface $intfname]} {
			    set skip [dict get $dict meta Internal.Prune]
			    if {[string is true -strict $skip]} continue
			}
		    }
		    set name [lindex [split $spec ,] 0]
		    if {[dict exists $intf method $name]} continue
		    # In case a method has neither input nor output arguments
		    dict set intf method $name {}
		    foreach n {in out} {
			foreach {arg sig} [dict get $dict $n] {
			    dict set intf method $name arg $arg {} \

			      [dict create type $sig direction $n]
			}
		    }

		    foreach {key value} [dict get $dict meta] {
			if {[string match Internal.* $key]} continue
			dict set intf method $name \
			  annotation org.freedesktop.DBus.$key {} value $value
		    }
		}
		# Signals
................................................................................
	    dict set rc node {} node $node {}
	}
    }
    return $rc
}

proc dbus::dbif::xmlize {dict} {

    dict for {tag data} $dict {
	dict for {name spec} $data {
	    set str $tag
	    set lines {}
	    if {$name ne {}} {append str [format { name="%s"} $name]}
	    if {[dict exists $spec {}]} {
		dict for {attrib value} [dict get $spec {}] {
		    append str [format { %s="%s"} $attrib $value]
		}
................................................................................
    # Allow 25 seconds for the application to provide a response
    set afterid [after $timeout [list dbus::dbif::expire $id]]
    set info($id) [dict merge $data [dict create bus $dbus afterid $afterid]]
    # Store a copy of the information needed to provide a response. This
    # information would otherwise be lost if the code deletes its own path.
    dict set info($id) resp $dict
    dict with dict {
    	if {[catch {interp eval $interp \
	  [list uplevel #0 $command [linsert $args 0 $id]]} result opts]} {
	    respond error $id $result
	} elseif {$async || [async $opts]} {
    	    # Keep the message information around for a bit more
	} elseif {$noreply} {
	    expire $id
	} elseif {[info exists info($id)]} {
	    respond return $id $result
................................................................................
    if {![dict exists $hear($dbus,$path,$interface) $member,$signature]} return

    set id message[incr msgid]
    set info($id) [dict merge $data [dict create bus $dbus afterid $id]]
    set dict [dict get $hear($dbus,$path,$interface) $member,$signature]
    catch {
	dict with dict {
	    interp eval $interp [list uplevel #0 $command [linsert $args 0 $id]]
	}
    }
    # Clean up
    expire $id
}







|
|
|







 







<







 







|






|




|







 







|
<
|
|
|
<
<
<
<
<
<







 







|







 







|






<
<
<
<
<
<
<







|

|







 







|






<
<
<
<
<
<







 







|





|




<
<
<







|







 







|


|


|







 







<





|







 







|







 







|


|







 







<
|






|







 







<

|



|







 







<

|

|







 







<
|







 







|







 







|
<


<
>
|


>







 







>

|







 







<
|







 







|





2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
..
38
39
40
41
42
43
44

45
46
47
48
49
50
51
...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
...
256
257
258
259
260
261
262
263

264
265
266






267
268
269
270
271
272
273
...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
...
481
482
483
484
485
486
487
488
489
490
491
492
493
494







495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
...
536
537
538
539
540
541
542
543
544
545
546
547
548
549






550
551
552
553
554
555
556
...
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591



592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
...
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
...
638
639
640
641
642
643
644

645
646
647
648
649
650
651
652
653
654
655
656
657
...
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
...
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
...
810
811
812
813
814
815
816

817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
...
838
839
840
841
842
843
844

845
846
847
848
849
850
851
852
853
854
855
856
857
...
862
863
864
865
866
867
868

869
870
871
872
873
874
875
876
877
878
879
...
908
909
910
911
912
913
914

915
916
917
918
919
920
921
922
...
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
...
973
974
975
976
977
978
979
980

981
982

983
984
985
986
987
988
989
990
991
992
993
994
....
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
....
1143
1144
1145
1146
1147
1148
1149

1150
1151
1152
1153
1154
1155
1156
1157
....
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
# provide a number of standard DBus interfaces in a Tcl application.
#
# The following interfaces are supported:
#	org.freedesktop.DBus.Peer
#	org.freedesktop.DBus.Introspectable
#	org.freedesktop.DBus.Properties

package require dbus 3.0
package provide dbif 2.0
package provide dbus-intf 2.0

namespace eval dbus::dbif {
    # Setup some defaults in case the user doesn't specify certain options
    variable defaults [dict create bus session intf com.tclcode.default]

    # Mapping of bus names to dbus handles
    variable handle {}
................................................................................
    set signal(PropertiesChanged) {
	dbus ""
	path ""
	interface org.freedesktop.DBus.Properties
	name PropertiesChanged
	signature sa{sv}as
	command ::dbus::dbif::propchanged

	meta {}
	args {
	    interface_name s
	    changed_properties a{sv}
	    invalidated_properties as
	}
    }
................................................................................
    }
    return [dict create signature $signature args $args]
}

# Define a method that can be called over the DBus
#
proc dbus::dbif::define \
  {dbus path intf name cmd {in {}} {out {}} {meta {}} {async 0}} {
    variable dbif
    create $dbus $path $intf
    set args [args $in]
    dict update args signature sig args inargs {}
    set args [args $out]
    dict update args signature ret args outargs {}
    set dict [dict create command $cmd signature $ret \
      in $inargs out $outargs meta $meta async $async]
    dict set dbif($dbus|$path|$intf) methods $name,$sig $dict
}

proc dbus::dbif::undefine {dbus path intf name cmd {in {}}} {
    variable dbif
    if {![info exists dbif($dbus|$path|$intf)]} return
    set args [args $in]
    dict update args signature sig args inargs {}
    dict unset dbif($dbus|$path|$intf) methods $name,$sig
}

................................................................................
	}
	set arglist [lassign $arglist var]
    }
}

# Get the namespace of the caller
#
proc dbus::dbif::getns {} {

    # This is a helper procedure. So 1 level up is the actual procedure
    # We need to go 2 levels up for the caller of the actual procedure
    return [uplevel 2 [list namespace current]]






}

# Access the miscellaneous information of a message
#
proc dbus::dbif::get {id name} {
    variable info
    if {![info exists info($id)]} {
................................................................................
	    if {!$trace} return
	    if {$access ni {read readwrite}} return
	    if {$ecs ni {true invalidates}} return
	}
	set inv [expr {$ecs eq "invalidates"}]
	set trc [list dbus::dbif::propchg $dbus $path $intf $name $inv]
	set cmd [list trace $op variable $variable {write unset} $trc]
	uplevel #0 $cmd
    }
    return
}

# Needs to be exposed via the regular API?
proc dbus::dbif::changedsignal {state} {
    variable trace
................................................................................

# Define a signal that the application may send
#
proc dbus::dbif::signal {args} {
    variable defaults; variable dbif; variable signal; variable sigid
    dict with defaults {}; set meta {}
    set id ""
    cmdline opt arg {path name {in {}} {arglist {}} {body {}}} $args {
	-id: {set id $arg}
	-bus: {set bus [buscheck $arg]}
	-interface: {set intf [intfcheck $arg]}
	-attributes: {set meta [metacheck $arg]}
    }
    set dbus [handle $bus]







    if {$name ne ""} {
	namecheck $name
	# Signals without a predefined path need a body to provide the path
	if {$path ne "" || $body eq ""} {pathcheck $path}
	create $dbus $path $intf
	if {$id eq ""} {set id signal[incr sigid]}
	set dict [dict create dbus $dbus path $path \
	  interface $intf name $name command ""]
	if {$body ne ""} {
	    set ns [getns]
	    dict set dict command [list apply [list $arglist $body $ns]]
	}
    }
    if {[info exists signal($id)]} {
	# Clean up the old signal
	dict update signal($id) dbus obus path opath interface ointf {}
	if {$obus eq ""} {
................................................................................
}

# Define a property that may be accessed through the DBus
#
proc dbus::dbif::property {args} {
    variable defaults; variable dbif
    dict with defaults {}; set op readwrite; set meta {}
    cmdline opt arg {path name var {body ""}} $args {
	-bus: {set bus [buscheck $arg]}
	-interface: {set intf [intfcheck $arg]}
	-access: {set op [accesscheck $arg]}
	-attributes: {set meta [metacheck $arg]}
    }
    set dbus [handle $bus]






    set args [args [list $name] Property]
    set name [lindex [dict get $args args] 0]
    set sig [lindex [dict get $args signature] 0]
    # Properties should be a single complete type, otherwise
    # GetAll will produce invalid results
    set cnt [argcount [list $name $sig]]
    if {$cnt != 1} {
................................................................................

    if {$var eq {}} {
	dict unset $dbif($dbus|$path|$intf) properties $name
	return
    }
	
    if {$body ne ""} {
	set ns [getns]
	set cmd [list apply [list [list msgid $name] $body $ns]]
    } else {
	set cmd ""
    }
    set dict [dict create variable $var access $op signature $sig \
      command $cmd meta $meta]
    dict set dbif($dbus|$path|$intf) properties $name $dict

    # Setup a variable trace for readable properties
    vartrace add $dbus $path $intf $name



}

# Define how to handle a method call
#
proc dbus::dbif::method {args} {
    variable defaults
    dict with defaults {}; set meta {}; set async 0; set opts {}
    cmdline opt arg {path cmd {in ""} {out ""} body} $args {
        -bus: {set bus [buscheck $arg]}
        -interface: {set intf [intfcheck $arg]}
	-attributes: {set meta [metacheck $arg]}
	-async {set async 1}
	-details {lappend opts -details}
    }
    set dbus [handle $bus]
................................................................................
	    lassign [split $n :] name sig
	    lappend args $name
	    lset info 0 [linsert [lindex $info 0] end $n]
	}
    }
    if {$body eq {}} {
	foreach n $info {
	    undefine $dbus $path $intf $cmd $n
	}
    } else {
	set ns [getns]
	set code [list apply [list [linsert $args 0 msgid] $body $ns]]
	foreach n $info {
	    define $dbus $path $intf $cmd $code $n $out $meta $async
	}
	dbus method $dbus {*}$opts \
	  $path $intf.$cmd [list dbus::dbif::methods $dbus]
    }
}

# Generate a signal according to an earlier specification
................................................................................
#
proc dbus::dbif::generate {id args} {
    variable signal
    if {![info exists signal($id)]} {
	error "Signal '$id' has not been defined"
    }
    set cmd [dict get $signal($id) command]

    if {$cmd eq ""} {
    	set argv $args
	dict with signal($id) {}
    } else {
	# Need to use catch to get the additional return options
	if {[catch {uplevel #0 $cmd $args} argv opts]} {
	    # Rethrow any exceptions
	    return -options $opts $argv
	}
	dict with signal($id) {}
	if {$path eq ""} {
	    # Standard signal, body code must have provided the path
	    if {[dict exists $opts -path]} {
................................................................................
}

# Setup a signal handler for a specific signal
#
proc dbus::dbif::listen {args} {
    variable defaults; variable hear
    dict with defaults {}
    cmdline opt arg {path name {arglist ""} body} $args {
        -bus: {set bus [buscheck $arg]}
        -interface: {set intf [intfcheck $arg]}
    }
    set dbus [handle $bus]
    dbus filter $dbus add \
      -type signal -path $path -interface $intf -member $name
    set args {}
................................................................................
	} else {
	    lassign [split $n :] var sig
	    if {$sig eq ""} {set sig s}
	    lappend args $var
	    lset info 0 [lindex $info 0]$sig
	}
    }
    set ns [getns]
    set code [list apply [list [linsert $args 0 msgid] $body $ns]]
    foreach n $info {
    	set dict [dict create command $code]
    	dict set hear($dbus,$path,$intf) $name,$n $dict
    }
    dbus listen $dbus $path $intf.$name [list dbus::dbif::signals $dbus]
}

# Send a response to a DBus message
#
................................................................................
	    dbuserr signature $dbus $path $intf $name $sig $signature
    	}
	if {$command ne ""} {
	    set id message[incr msgid]
	    set afterid [after $timeout [list dbus::dbif::expire $id]]
	    set info($id) \
	      [dict merge $data [dict create bus $dbus afterid $afterid]]

	    if {[catch {uplevel #0 [linsert $command end $id $arg]} res opts]} {
		expire $id
		# Rethrow the error so it gets reported back to the caller
		return -options [dict incr opts -level] $res
	    }
	    expire $id
	}
	uplevel #0 [list set $variable $arg]
    }
    dict with data {
    	dbus return $dbus $sender $serial
    }
    return -async 1
}

................................................................................
	dbuserr interface $dbus $path $intf
    }
    if {![dict exists $dbif($dbus|$path|$intf) properties $name]} {
	dbuserr property $dbus $path $intf $name
    }
    set op [dict get $dbif($dbus|$path|$intf) properties $name access]
    if {$op ni {read readwrite}} {dbuserr access $dbus $path $intf $name read}

    set var [dict get $dbif($dbus|$path|$intf) properties $name variable]
    if {[uplevel #0 [list info exists $var]]} {
	set sig [dict get $dbif($dbus|$path|$intf) properties $name signature]
	set dest [dict get $data sender]
	set serial [dict get $data serial]
	set value [uplevel #0 [list set $var]]
	dbus return $dbus -signature $sig $dest $serial $value
    } else {
	dbuserr propunset $dbus $path $intf $name
    }
    return -async 1
}

................................................................................
    set path [dict get $data path]
    if {![info exists dbif($dbus|$path|$intf)]} {
	dbuserr interface $dbus $path $intf
    }
    if {![dict exists $dbif($dbus|$path|$intf) properties]} {return {}}
    set rc {}
    dict for {n v} [dict get $dbif($dbus|$path|$intf) properties] {

	set var [dict get $v variable]
	if {[uplevel #0 [list info exists $var]]} {
	    set sig [dict get $v signature]
	    set value [uplevel #0 [list set $var]]
	    lappend rc $n [list $sig $value]
	}
    }
    dict with data {
 	dbus return $dbus -signature a{sv} $sender $serial $rc
    }
    return -async 1
................................................................................
    variable dbif
    set change {}
    set invalid {}
    dict for {key op} [dict get $propchg $dbus $path $intf] {
	if {$op eq "write"} {
	    set info [dict get $dbif($dbus|$path|$intf) properties $key]
	    dict with info {}

	    set value [uplevel #0 [list set $variable]]
	    dict set change $key [list $signature $value]
	} else {
	    lappend invalid $key
	}
    }
    dict unset propchg $dbus $path $intf
    variable signal
................................................................................
		    # Report values that do not match the signature
		    if {[catch {generate PropertiesChanged \
		      $path $intf $dbus} msg opts]} {
			set str "failed to generate the PropertiesChanged\
			  dbus signal for interface '$intf' on path '$path'.\
			  Reason: $msg"
			dict set opts -errorinfo $str
			# Get the error reporting command
			set errcmd [interp bgerror {}]
			# Report the error without throwing an exception
			catch {{*}$errcmd $str $opts}
		    }
		}
	    }
	}
................................................................................
			if {![dict exists $init node {} interface $intfname]} {
			    set skip [dict get $dict meta Internal.Prune]
			    if {[string is true -strict $skip]} continue
			}
		    }
		    set name [lindex [split $spec ,] 0]
		    if {[dict exists $intf method $name]} continue
		    set args {}

		    foreach n {in out} {
			foreach {arg sig} [dict get $dict $n] {

			    lappend args $arg [dict create {} \
			      [dict create type $sig direction $n]]
			}
		    }
		    dict set intf method $name arg $args
		    foreach {key value} [dict get $dict meta] {
			if {[string match Internal.* $key]} continue
			dict set intf method $name \
			  annotation org.freedesktop.DBus.$key {} value $value
		    }
		}
		# Signals
................................................................................
	    dict set rc node {} node $node {}
	}
    }
    return $rc
}

proc dbus::dbif::xmlize {dict} {
    set rc {}
    dict for {tag data} $dict {
	foreach {name spec} $data {
	    set str $tag
	    set lines {}
	    if {$name ne {}} {append str [format { name="%s"} $name]}
	    if {[dict exists $spec {}]} {
		dict for {attrib value} [dict get $spec {}] {
		    append str [format { %s="%s"} $attrib $value]
		}
................................................................................
    # Allow 25 seconds for the application to provide a response
    set afterid [after $timeout [list dbus::dbif::expire $id]]
    set info($id) [dict merge $data [dict create bus $dbus afterid $afterid]]
    # Store a copy of the information needed to provide a response. This
    # information would otherwise be lost if the code deletes its own path.
    dict set info($id) resp $dict
    dict with dict {

    	if {[catch {uplevel #0 $command [linsert $args 0 $id]} result opts]} {
	    respond error $id $result
	} elseif {$async || [async $opts]} {
    	    # Keep the message information around for a bit more
	} elseif {$noreply} {
	    expire $id
	} elseif {[info exists info($id)]} {
	    respond return $id $result
................................................................................
    if {![dict exists $hear($dbus,$path,$interface) $member,$signature]} return

    set id message[incr msgid]
    set info($id) [dict merge $data [dict create bus $dbus afterid $id]]
    set dict [dict get $hear($dbus,$path,$interface) $member,$signature]
    catch {
	dict with dict {
	    uplevel #0 $command [linsert $args 0 $id]
	}
    }
    # Clean up
    expire $id
}

Changes to doc/dbif.man.

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
[arg bus], [arg member], [arg interface], [arg path], [arg sender],
[arg destination], [arg messagetype], [arg signature], [arg serial],
[arg replyserial], [arg noreply], [arg autostart], and [arg errorname].

[call [cmd [vset cmdname]] [method listen] \
  [opt "[option -bus] [arg bustype]"] \
  [opt "[option -interface] [arg interface]"] \
  [arg path] [arg name] [opt [arg arglist]] [opt [arg interp]] [arg body]]

Start listening for the specified signal and execute [arg body] when such a
signal appears on the D-Bus.

[para]

The code in [arg body] will be executed in the namespace the
................................................................................
argument lists. See [sectref "ARGUMENT LISTS"] below for more information.

[call [cmd [vset cmdname]] [method method] \
  [opt "[option -attributes] [arg attributes]"] \
  [opt "[option -bus] [arg bustype]"] \
  [opt "[option -interface] [arg interface]"] \
  [arg path] [arg name] \
  [opt "[arg inputargs] [opt [arg outputargs]]"] [opt [arg interp]] [arg body]]

Define a method that may be accessed through the D-Bus and execute [arg body]
when the method is invoked. 
In addition to valid dbus paths, an empty string may be specified for the
[arg path] argument. This makes the method available on all paths.
The [arg inputargs] argument specifies which arguments must be provided by
the caller. The [arg outputargs] argument indicates the type of result the
................................................................................

[call [cmd [vset cmdname]] [method property] \
  [opt "[option -access] [arg mode]"] \
  [opt "[option -attributes] [arg attributes]"] \
  [opt "[option -bus] [arg bustype]"] \
  [opt "[option -interface] [arg interface]"] \
  [arg path] [arg name]?:[arg signature]? [arg variable] \
  [opt "[opt [arg interp]] [arg body]"]]

Define a property that may be accessed through the D-Bus using methods defined 
by the org.freedesktop.DBus.Properties standard interface. The [arg variable]
argument defines the global variable holding the value of the property.

The [arg signature] of a property must be a single complete type.
[para]
................................................................................
name as the property. If execution of [arg body] results in an error, the
global variable will not be modified. This allows restrictions to be imposed
on the value for the property.

[para]

The code in [arg body] will be executed in the namespace the
[cmd [vset cmdname]] [method property] command was issued from or, if a slave
interpreter was specified, in the current namespace of that slave interpreter
at definition time.

[para]

Generating the property value only when needed can be implemented by putting
a read trace on the global variable. Example:
[example_begin]
dbif property -attributes {Property.EmitsChangedSignal false} / clock sec
................................................................................

[call [cmd [vset cmdname]] [method signal] \
  [opt "[option -attributes] [arg attributes]"] \
  [opt "[option -bus] [arg bustype]"] \
  [opt "[option -id] [arg signalID]"] \
  [opt "[option -interface] [arg interface]"] \
  [arg path] [arg name] \
  [opt "[arg arglist] [opt "[opt [arg interp]] [arg args] [arg body]"]"]]

Define a signal that the application may emit using the [cmd [vset cmdname]]
[method generate] subcommand. Signals are referred to by their SignalID.
If [option -id] is specified, it is used as the SignalID. Otherwise a new
unique identifier is generated. Specifying an existing SignalID replaces
the previously defined signal.








|







 







|







 







|







 







|
<
<







 







|







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
...
243
244
245
246
247
248
249
250


251
252
253
254
255
256
257
...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
[arg bus], [arg member], [arg interface], [arg path], [arg sender],
[arg destination], [arg messagetype], [arg signature], [arg serial],
[arg replyserial], [arg noreply], [arg autostart], and [arg errorname].

[call [cmd [vset cmdname]] [method listen] \
  [opt "[option -bus] [arg bustype]"] \
  [opt "[option -interface] [arg interface]"] \
  [arg path] [arg name] [opt [arg arglist]] [arg body]]

Start listening for the specified signal and execute [arg body] when such a
signal appears on the D-Bus.

[para]

The code in [arg body] will be executed in the namespace the
................................................................................
argument lists. See [sectref "ARGUMENT LISTS"] below for more information.

[call [cmd [vset cmdname]] [method method] \
  [opt "[option -attributes] [arg attributes]"] \
  [opt "[option -bus] [arg bustype]"] \
  [opt "[option -interface] [arg interface]"] \
  [arg path] [arg name] \
  [opt "[arg inputargs] [opt [arg outputargs]]"] [arg body]]

Define a method that may be accessed through the D-Bus and execute [arg body]
when the method is invoked. 
In addition to valid dbus paths, an empty string may be specified for the
[arg path] argument. This makes the method available on all paths.
The [arg inputargs] argument specifies which arguments must be provided by
the caller. The [arg outputargs] argument indicates the type of result the
................................................................................

[call [cmd [vset cmdname]] [method property] \
  [opt "[option -access] [arg mode]"] \
  [opt "[option -attributes] [arg attributes]"] \
  [opt "[option -bus] [arg bustype]"] \
  [opt "[option -interface] [arg interface]"] \
  [arg path] [arg name]?:[arg signature]? [arg variable] \
  [opt [arg body]]]

Define a property that may be accessed through the D-Bus using methods defined 
by the org.freedesktop.DBus.Properties standard interface. The [arg variable]
argument defines the global variable holding the value of the property.

The [arg signature] of a property must be a single complete type.
[para]
................................................................................
name as the property. If execution of [arg body] results in an error, the
global variable will not be modified. This allows restrictions to be imposed
on the value for the property.

[para]

The code in [arg body] will be executed in the namespace the
[cmd [vset cmdname]] [method property] command was issued from.



[para]

Generating the property value only when needed can be implemented by putting
a read trace on the global variable. Example:
[example_begin]
dbif property -attributes {Property.EmitsChangedSignal false} / clock sec
................................................................................

[call [cmd [vset cmdname]] [method signal] \
  [opt "[option -attributes] [arg attributes]"] \
  [opt "[option -bus] [arg bustype]"] \
  [opt "[option -id] [arg signalID]"] \
  [opt "[option -interface] [arg interface]"] \
  [arg path] [arg name] \
  [opt "[arg arglist] [opt "[arg args] [arg body]"]"]]

Define a signal that the application may emit using the [cmd [vset cmdname]]
[method generate] subcommand. Signals are referred to by their SignalID.
If [option -id] is specified, it is used as the SignalID. Otherwise a new
unique identifier is generated. Specifying an existing SignalID replaces
the previously defined signal.