(root)/
glib-2.79.0/
gio/
tests/
gdbus-testserver.c
       1  #include <gio/gio.h>
       2  #include <stdlib.h>
       3  
       4  static GDBusNodeInfo *introspection_data = NULL;
       5  static GMainLoop *loop = NULL;
       6  static GHashTable *properties = NULL;
       7  
       8  static const gchar introspection_xml[] =
       9    "<node>"
      10    "  <interface name='com.example.Frob'>"
      11    "    <method name='Quit'>"
      12    "    </method>"
      13    "    <method name='TestArrayOfStringTypes'>"
      14    "      <arg direction='in'  type='as' name='val_string' />"
      15    "      <arg direction='in'  type='ao' name='val_objpath' />"
      16    "      <arg direction='in'  type='ag' name='val_signature' />"
      17    "      <arg direction='out' type='as' />"
      18    "      <arg direction='out' type='ao' />"
      19    "      <arg direction='out' type='ag' />"
      20    "    </method>"
      21    "    <method name='TestPrimitiveTypes'>"
      22    "      <arg direction='in'  type='y' name='val_byte' />"
      23    "      <arg direction='in'  type='b' name='val_boolean' />"
      24    "      <arg direction='in'  type='n' name='val_int16' />"
      25    "      <arg direction='in'  type='q' name='val_uint16' />"
      26    "      <arg direction='in'  type='i' name='val_int32' />"
      27    "      <arg direction='in'  type='u' name='val_uint32' />"
      28    "      <arg direction='in'  type='x' name='val_int64' />"
      29    "      <arg direction='in'  type='t' name='val_uint64' />"
      30    "      <arg direction='in'  type='d' name='val_double' />"
      31    "      <arg direction='in'  type='s' name='val_string' />"
      32    "      <arg direction='in'  type='o' name='val_objpath' />"
      33    "      <arg direction='in'  type='g' name='val_signature' />"
      34    "      <arg direction='out' type='y' />"
      35    "      <arg direction='out' type='b' />"
      36    "      <arg direction='out' type='n' />"
      37    "      <arg direction='out' type='q' />"
      38    "      <arg direction='out' type='i' />"
      39    "      <arg direction='out' type='u' />"
      40    "      <arg direction='out' type='x' />"
      41    "      <arg direction='out' type='t' />"
      42    "      <arg direction='out' type='d' />"
      43    "      <arg direction='out' type='s' />"
      44    "      <arg direction='out' type='o' />"
      45    "      <arg direction='out' type='g' />"
      46    "    </method>"
      47    "    <method name='EmitSignal'>"
      48    "      <arg direction='in'  type='s' name='str1' />"
      49    "      <arg direction='in'  type='o' name='objpath1' />"
      50    "    </method>"
      51    "    <method name='TestArrayOfPrimitiveTypes'>"
      52    "      <arg direction='in'  type='ay' name='val_byte' />"
      53    "      <arg direction='in'  type='ab' name='val_boolean' />"
      54    "      <arg direction='in'  type='an' name='val_int16' />"
      55    "      <arg direction='in'  type='aq' name='val_uint16' />"
      56    "      <arg direction='in'  type='ai' name='val_int32' />"
      57    "      <arg direction='in'  type='au' name='val_uint32' />"
      58    "      <arg direction='in'  type='ax' name='val_int64' />"
      59    "      <arg direction='in'  type='at' name='val_uint64' />"
      60    "      <arg direction='in'  type='ad' name='val_double' />"
      61    "      <arg direction='out' type='ay' />"
      62    "      <arg direction='out' type='ab' />"
      63    "      <arg direction='out' type='an' />"
      64    "      <arg direction='out' type='aq' />"
      65    "      <arg direction='out' type='ai' />"
      66    "      <arg direction='out' type='au' />"
      67    "      <arg direction='out' type='ax' />"
      68    "      <arg direction='out' type='at' />"
      69    "      <arg direction='out' type='ad' />"
      70    "    </method>"
      71    "    <method name='FrobSetProperty'>"
      72    "      <arg direction='in'  type='s' name='prop_name' />"
      73    "      <arg direction='in'  type='v' name='prop_value' />"
      74    "    </method>"
      75    "    <signal name='TestSignal'>"
      76    "      <arg type='s' name='str1' />"
      77    "      <arg type='o' name='objpath1' />"
      78    "      <arg type='v' name='variant1' />"
      79    "    </signal>"
      80    "    <method name='TestComplexArrays'>"
      81    "      <arg direction='in'  type='a(ii)' name='aii' />"
      82    "      <arg direction='in'  type='aa(ii)' name='aaii' />"
      83    "      <arg direction='in'  type='aas' name='aas' />"
      84    "      <arg direction='in'  type='aa{ss}' name='ahashes' />"
      85    "      <arg direction='in'  type='aay' name='aay' />"
      86    "      <arg direction='in'  type='av' name='av' />"
      87    "      <arg direction='in'  type='aav' name='aav' />"
      88    "      <arg direction='out' type='a(ii)' />"
      89    "      <arg direction='out' type='aa(ii)' />"
      90    "      <arg direction='out' type='aas' />"
      91    "      <arg direction='out' type='aa{ss}' />"
      92    "      <arg direction='out' type='aay' />"
      93    "      <arg direction='out' type='av' />"
      94    "      <arg direction='out' type='aav' />"
      95    "    </method>"
      96    "    <method name='TestVariant'>"
      97    "      <arg direction='in'  type='v' name='v' />"
      98    "      <arg direction='in'  type='b' name='modify' />"
      99    "      <arg direction='out' type='v' />"
     100    "    </method>"
     101    "    <method name='FrobInvalidateProperty'>"
     102    "      <arg direction='in'  type='s' name='new_value' />"
     103    "    </method>"
     104    "    <method name='HelloWorld'>"
     105    "      <arg direction='in'  type='s' name='hello_message' />"
     106    "      <arg direction='out' type='s' />"
     107    "    </method>"
     108    "    <method name='PairReturn'>"
     109    "      <arg direction='out' type='s' />"
     110    "      <arg direction='out' type='u' />"
     111    "    </method>"
     112    "    <method name='TestStructureTypes'>"
     113    "      <arg direction='in'  type='(ii)' name='s1' />"
     114    "      <arg direction='in'  type='(s(ii)aya{ss})' name='s2' />"
     115    "      <arg direction='out' type='(ii)' />"
     116    "      <arg direction='out' type='(s(ii)aya{ss})' />"
     117    "    </method>"
     118    "    <method name='EmitSignal2'>"
     119    "    </method>"
     120    "    <method name='DoubleHelloWorld'>"
     121    "      <arg direction='in'  type='s' name='hello1' />"
     122    "      <arg direction='in'  type='s' name='hello2' />"
     123    "      <arg direction='out' type='s' />"
     124    "      <arg direction='out' type='s' />"
     125    "    </method>"
     126    "    <method name='Sleep'>"
     127    "      <arg direction='in'  type='i' name='msec' />"
     128    "    </method>"
     129    "    <method name='TestHashTables'>"
     130    "      <arg direction='in'  type='a{yy}' name='hyy' />"
     131    "      <arg direction='in'  type='a{bb}' name='hbb' />"
     132    "      <arg direction='in'  type='a{nn}' name='hnn' />"
     133    "      <arg direction='in'  type='a{qq}' name='hqq' />"
     134    "      <arg direction='in'  type='a{ii}' name='hii' />"
     135    "      <arg direction='in'  type='a{uu}' name='huu' />"
     136    "      <arg direction='in'  type='a{xx}' name='hxx' />"
     137    "      <arg direction='in'  type='a{tt}' name='htt' />"
     138    "      <arg direction='in'  type='a{dd}' name='hdd' />"
     139    "      <arg direction='in'  type='a{ss}' name='hss' />"
     140    "      <arg direction='in'  type='a{oo}' name='hoo' />"
     141    "      <arg direction='in'  type='a{gg}' name='hgg' />"
     142    "      <arg direction='out' type='a{yy}' />"
     143    "      <arg direction='out' type='a{bb}' />"
     144    "      <arg direction='out' type='a{nn}' />"
     145    "      <arg direction='out' type='a{qq}' />"
     146    "      <arg direction='out' type='a{ii}' />"
     147    "      <arg direction='out' type='a{uu}' />"
     148    "      <arg direction='out' type='a{xx}' />"
     149    "      <arg direction='out' type='a{tt}' />"
     150    "      <arg direction='out' type='a{dd}' />"
     151    "      <arg direction='out' type='a{ss}' />"
     152    "      <arg direction='out' type='a{oo}' />"
     153    "      <arg direction='out' type='a{gg}' />"
     154    "    </method>"
     155    "    <signal name='TestSignal2'>"
     156    "      <arg type='i' name='int1' />"
     157    "    </signal>"
     158    "    <method name='TestComplexHashTables'>"
     159    "      <arg direction='in'  type='a{s(ii)}' name='h_str_to_pair' />"
     160    "      <arg direction='in'  type='a{sv}' name='h_str_to_variant' />"
     161    "      <arg direction='in'  type='a{sav}' name='h_str_to_av' />"
     162    "      <arg direction='in'  type='a{saav}' name='h_str_to_aav' />"
     163    "      <arg direction='in'  type='a{sa(ii)}' name='h_str_to_array_of_pairs' />"
     164    "      <arg direction='in'  type='a{sa{ss}}' name='hash_of_hashes' />"
     165    "      <arg direction='out' type='a{s(ii)}' />"
     166    "      <arg direction='out' type='a{sv}' />"
     167    "      <arg direction='out' type='a{sav}' />"
     168    "      <arg direction='out' type='a{saav}' />"
     169    "      <arg direction='out' type='a{sa(ii)}' />"
     170    "      <arg direction='out' type='a{sa{ss}}' />"
     171    "    </method>"
     172    "    <property type='y' name='y' access='readwrite' />"
     173    "    <property type='b' name='b' access='readwrite' />"
     174    "    <property type='n' name='n' access='readwrite' />"
     175    "    <property type='q' name='q' access='readwrite' />"
     176    "    <property type='i' name='i' access='readwrite' />"
     177    "    <property type='u' name='u' access='readwrite' />"
     178    "    <property type='x' name='x' access='readwrite' />"
     179    "    <property type='t' name='t' access='readwrite' />"
     180    "    <property type='d' name='d' access='readwrite' />"
     181    "    <property type='s' name='s' access='readwrite' />"
     182    "    <property type='o' name='o' access='readwrite' />"
     183    "    <property type='ay' name='ay' access='readwrite' />"
     184    "    <property type='ab' name='ab' access='readwrite' />"
     185    "    <property type='an' name='an' access='readwrite' />"
     186    "    <property type='aq' name='aq' access='readwrite' />"
     187    "    <property type='ai' name='ai' access='readwrite' />"
     188    "    <property type='au' name='au' access='readwrite' />"
     189    "    <property type='ax' name='ax' access='readwrite' />"
     190    "    <property type='at' name='at' access='readwrite' />"
     191    "    <property type='ad' name='ad' access='readwrite' />"
     192    "    <property type='as' name='as' access='readwrite' />"
     193    "    <property type='ao' name='ao' access='readwrite' />"
     194    "    <property type='s' name='foo' access='readwrite' />"
     195    "    <property type='s' name='PropertyThatWillBeInvalidated' access='readwrite' />"
     196    "  </interface>"
     197    "</node>";
     198  
     199  static gboolean
     200  end_sleep (gpointer data)
     201  {
     202    GDBusMethodInvocation *invocation = data;
     203  
     204    g_dbus_method_invocation_return_value (invocation, NULL);
     205    g_object_unref (invocation);
     206  
     207    return G_SOURCE_REMOVE;
     208  }
     209  
     210  static void
     211  handle_method_call (GDBusConnection       *connection,
     212                      const gchar           *sender,
     213                      const gchar           *object_path,
     214                      const gchar           *interface_name,
     215                      const gchar           *method_name,
     216                      GVariant              *parameters,
     217                      GDBusMethodInvocation *invocation,
     218                      gpointer               user_data)
     219  {
     220    if (g_strcmp0 (method_name, "HelloWorld") == 0)
     221      {
     222        const gchar *greeting;
     223  
     224        g_variant_get (parameters, "(&s)", &greeting);
     225        if (g_strcmp0 (greeting, "Yo") == 0)
     226          {
     227            g_dbus_method_invocation_return_dbus_error (invocation,
     228                                                        "com.example.TestException",
     229                                                        "Yo is not a proper greeting");
     230          }
     231        else
     232          {
     233            gchar *response;
     234            response = g_strdup_printf ("You greeted me with '%s'. Thanks!", greeting);
     235            g_dbus_method_invocation_return_value (invocation,
     236                                                   g_variant_new ("(s)", response));
     237            g_free ( response);
     238          }
     239      }
     240    else if (g_strcmp0 (method_name, "DoubleHelloWorld") == 0)
     241      {
     242        const gchar *hello1, *hello2;
     243        gchar *reply1, *reply2;
     244  
     245        g_variant_get (parameters, "(&s&s)", &hello1, &hello2);
     246        reply1 = g_strdup_printf ("You greeted me with '%s'. Thanks!", hello1);
     247        reply2 = g_strdup_printf ("Yo dawg, you uttered '%s'. Thanks!", hello2);
     248        g_dbus_method_invocation_return_value (invocation,
     249                                               g_variant_new ("(ss)", reply1, reply2));
     250        g_free (reply1);
     251        g_free (reply2);
     252      }
     253    else if (g_strcmp0 (method_name, "PairReturn") == 0)
     254      {
     255        g_dbus_method_invocation_return_value (invocation,
     256                                               g_variant_new ("(su)", "foo", 42));
     257      }
     258    else if (g_strcmp0 (method_name, "TestPrimitiveTypes") == 0)
     259      {
     260        guchar val_byte;
     261        gboolean val_boolean;
     262        gint16 val_int16;
     263        guint16 val_uint16;
     264        gint32 val_int32;
     265        guint32 val_uint32;
     266        gint64 val_int64;
     267        guint64 val_uint64;
     268        gdouble val_double;
     269        const gchar *val_string;
     270        const gchar *val_objpath;
     271        const gchar *val_signature;
     272        gchar *ret_string;
     273        gchar *ret_objpath;
     274        gchar *ret_signature;
     275  
     276        g_variant_get (parameters, "(ybnqiuxtd&s&o&g)",
     277                       &val_byte,
     278                       &val_boolean,
     279                       &val_int16,
     280                       &val_uint16,
     281                       &val_int32,
     282                       &val_uint32,
     283                       &val_int64,
     284                       &val_uint64,
     285                       &val_double,
     286                       &val_string,
     287                       &val_objpath,
     288                       &val_signature);
     289  
     290        ret_string = g_strconcat (val_string, val_string, NULL);
     291        ret_objpath = g_strconcat (val_objpath, "/modified", NULL);
     292        ret_signature = g_strconcat (val_signature, val_signature, NULL);
     293  
     294        g_dbus_method_invocation_return_value (invocation,
     295            g_variant_new ("(ybnqiuxtdsog)",
     296                           val_byte + 1,
     297                           !val_boolean,
     298                           val_int16 + 1,
     299                           val_uint16 + 1,
     300                           val_int32 + 1,
     301                           val_uint32 + 1,
     302                           val_int64 + 1,
     303                           val_uint64 + 1,
     304                           - val_double + 0.123,
     305                           ret_string,
     306                           ret_objpath,
     307                           ret_signature));
     308  
     309        g_free (ret_string);
     310        g_free (ret_objpath);
     311        g_free (ret_signature);
     312      }
     313    else if (g_strcmp0 (method_name, "TestArrayOfPrimitiveTypes") == 0)
     314      {
     315        GVariant *v;
     316        const guchar *bytes;
     317        const gint16 *int16s;
     318        const guint16 *uint16s;
     319        const gint32 *int32s;
     320        const guint32 *uint32s;
     321        const gint64 *int64s;
     322        const guint64 *uint64s;
     323        const gdouble *doubles;
     324        gsize n_elts;
     325        gsize i, j;
     326        GVariantBuilder ret;
     327  
     328        g_variant_builder_init (&ret, G_VARIANT_TYPE ("(ayabanaqaiauaxatad)"));
     329  
     330        v = g_variant_get_child_value (parameters, 0);
     331        bytes = g_variant_get_fixed_array (v, &n_elts, 1);
     332        g_variant_builder_open (&ret, G_VARIANT_TYPE ("ay"));
     333        for (j = 0; j < 2; j++)
     334          for (i = 0; i < n_elts; i++)
     335            g_variant_builder_add (&ret, "y", bytes[i]);
     336        g_variant_builder_close (&ret);
     337        g_variant_unref (v);
     338  
     339        v = g_variant_get_child_value (parameters, 1);
     340        bytes = g_variant_get_fixed_array (v, &n_elts, 1);
     341        g_variant_builder_open (&ret, G_VARIANT_TYPE ("ab"));
     342        for (j = 0; j < 2; j++)
     343          for (i = 0; i < n_elts; i++)
     344            g_variant_builder_add (&ret, "b", (gboolean)bytes[i]);
     345        g_variant_builder_close (&ret);
     346        g_variant_unref (v);
     347  
     348        v = g_variant_get_child_value (parameters, 2);
     349        int16s = g_variant_get_fixed_array (v, &n_elts, 2);
     350        g_variant_builder_open (&ret, G_VARIANT_TYPE ("an"));
     351        for (j = 0; j < 2; j++)
     352          for (i = 0; i < n_elts; i++)
     353            g_variant_builder_add (&ret, "n", int16s[i]);
     354        g_variant_builder_close (&ret);
     355        g_variant_unref (v);
     356  
     357        v = g_variant_get_child_value (parameters, 3);
     358        uint16s = g_variant_get_fixed_array (v, &n_elts, 2);
     359        g_variant_builder_open (&ret, G_VARIANT_TYPE ("aq"));
     360        for (j = 0; j < 2; j++)
     361          for (i = 0; i < n_elts; i++)
     362            g_variant_builder_add (&ret, "q", uint16s[i]);
     363        g_variant_builder_close (&ret);
     364        g_variant_unref (v);
     365  
     366        v = g_variant_get_child_value (parameters, 4);
     367        int32s = g_variant_get_fixed_array (v, &n_elts, 4);
     368        g_variant_builder_open (&ret, G_VARIANT_TYPE ("ai"));
     369        for (j = 0; j < 2; j++)
     370          for (i = 0; i < n_elts; i++)
     371            g_variant_builder_add (&ret, "i", int32s[i]);
     372        g_variant_builder_close (&ret);
     373        g_variant_unref (v);
     374  
     375        v = g_variant_get_child_value (parameters, 5);
     376        uint32s = g_variant_get_fixed_array (v, &n_elts, 4);
     377        g_variant_builder_open (&ret, G_VARIANT_TYPE ("au"));
     378        for (j = 0; j < 2; j++)
     379          for (i = 0; i < n_elts; i++)
     380            g_variant_builder_add (&ret, "u", uint32s[i]);
     381        g_variant_builder_close (&ret);
     382        g_variant_unref (v);
     383  
     384        v = g_variant_get_child_value (parameters, 6);
     385        int64s = g_variant_get_fixed_array (v, &n_elts, 8);
     386        g_variant_builder_open (&ret, G_VARIANT_TYPE ("ax"));
     387        for (j = 0; j < 2; j++)
     388          for (i = 0; i < n_elts; i++)
     389            g_variant_builder_add (&ret, "x", int64s[i]);
     390        g_variant_builder_close (&ret);
     391        g_variant_unref (v);
     392  
     393        v = g_variant_get_child_value (parameters, 7);
     394        uint64s = g_variant_get_fixed_array (v, &n_elts, 8);
     395        g_variant_builder_open (&ret, G_VARIANT_TYPE ("at"));
     396        for (j = 0; j < 2; j++)
     397          for (i = 0; i < n_elts; i++)
     398            g_variant_builder_add (&ret, "t", uint64s[i]);
     399        g_variant_builder_close (&ret);
     400        g_variant_unref (v);
     401  
     402        v = g_variant_get_child_value (parameters, 8);
     403        doubles = g_variant_get_fixed_array (v, &n_elts, sizeof (gdouble));
     404        g_variant_builder_open (&ret, G_VARIANT_TYPE ("ad"));
     405        for (j = 0; j < 2; j++)
     406          for (i = 0; i < n_elts; i++)
     407            g_variant_builder_add (&ret, "d", doubles[i]);
     408        g_variant_builder_close (&ret);
     409        g_variant_unref (v);
     410  
     411        g_dbus_method_invocation_return_value (invocation,
     412                                               g_variant_builder_end (&ret));
     413      }
     414    else if (g_strcmp0 (method_name, "TestArrayOfStringTypes") == 0)
     415      {
     416        GVariantIter *iter1;
     417        GVariantIter *iter2;
     418        GVariantIter *iter3;
     419        GVariantIter *iter;
     420        GVariantBuilder ret;
     421        const gchar *s;
     422        gint i;
     423  
     424        g_variant_builder_init (&ret, G_VARIANT_TYPE ("(asaoag)"));
     425        g_variant_get (parameters, "(asaoag)", &iter1, &iter2, &iter3);
     426  
     427        g_variant_builder_open (&ret, G_VARIANT_TYPE ("as"));
     428        for (i = 0; i < 2; i++)
     429          {
     430            iter = g_variant_iter_copy (iter1);
     431            while (g_variant_iter_loop (iter, "s", &s))
     432              g_variant_builder_add (&ret, "s", s);
     433            g_variant_iter_free (iter);
     434          }
     435        g_variant_builder_close (&ret);
     436  
     437        g_variant_builder_open (&ret, G_VARIANT_TYPE ("ao"));
     438        for (i = 0; i < 2; i++)
     439          {
     440            iter = g_variant_iter_copy (iter1);
     441            while (g_variant_iter_loop (iter, "o", &s))
     442              g_variant_builder_add (&ret, "o", s);
     443            g_variant_iter_free (iter);
     444          }
     445        g_variant_builder_close (&ret);
     446  
     447        g_variant_builder_open (&ret, G_VARIANT_TYPE ("ag"));
     448        for (i = 0; i < 2; i++)
     449          {
     450            iter = g_variant_iter_copy (iter1);
     451            while (g_variant_iter_loop (iter, "g", &s))
     452              g_variant_builder_add (&ret, "g", s);
     453            g_variant_iter_free (iter);
     454          }
     455        g_variant_builder_close (&ret);
     456  
     457        g_variant_iter_free (iter1);
     458        g_variant_iter_free (iter2);
     459        g_variant_iter_free (iter3);
     460  
     461        g_dbus_method_invocation_return_value (invocation,
     462                                               g_variant_builder_end (&ret));
     463      }
     464    else if (g_strcmp0 (method_name, "TestHashTables") == 0)
     465      {
     466        GVariant *v;
     467        GVariantIter iter;
     468        GVariantBuilder ret;
     469        guint8 y1, y2;
     470        gboolean b1, b2;
     471        gint16 n1, n2;
     472        guint16 q1, q2;
     473        gint i1, i2;
     474        guint u1, u2;
     475        gint64 x1, x2;
     476        guint64 t1, t2;
     477        gdouble d1, d2;
     478        gchar *s1, *s2;
     479  
     480        g_variant_builder_init (&ret, G_VARIANT_TYPE ("(a{yy}a{bb}a{nn}a{qq}a{ii}a{uu}a{xx}a{tt}a{dd}a{ss}a{oo}a{gg})"));
     481  
     482        g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{yy}"));
     483        v = g_variant_get_child_value (parameters, 0);
     484        g_variant_iter_init (&iter, v);
     485        while (g_variant_iter_loop (&iter, "yy", &y1, &y2))
     486          g_variant_builder_add (&ret, "{yy}", y1 * 2, (y2 * 3) & 255);
     487        g_variant_unref (v);
     488        g_variant_builder_close (&ret);
     489  
     490        g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{bb}"));
     491        v = g_variant_get_child_value (parameters, 1);
     492        g_variant_iter_init (&iter, v);
     493        while (g_variant_iter_loop (&iter, "bb", &b1, &b2))
     494          g_variant_builder_add (&ret, "{bb}", b1, TRUE);
     495        g_variant_unref (v);
     496        g_variant_builder_close (&ret);
     497  
     498        g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{nn}"));
     499        v = g_variant_get_child_value (parameters, 2);
     500        g_variant_iter_init (&iter, v);
     501        while (g_variant_iter_loop (&iter, "nn", &n1, &n2))
     502          g_variant_builder_add (&ret, "{nn}", n1 * 2, n2 * 3);
     503        g_variant_unref (v);
     504        g_variant_builder_close (&ret);
     505  
     506        g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{qq}"));
     507        v = g_variant_get_child_value (parameters, 3);
     508        g_variant_iter_init (&iter, v);
     509        while (g_variant_iter_loop (&iter, "qq", &q1, &q2))
     510          g_variant_builder_add (&ret, "{qq}", q1 * 2, q2 * 3);
     511        g_variant_unref (v);
     512        g_variant_builder_close (&ret);
     513  
     514        g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{ii}"));
     515        v = g_variant_get_child_value (parameters, 4);
     516        g_variant_iter_init (&iter, v);
     517        while (g_variant_iter_loop (&iter, "ii", &i1, &i2))
     518          g_variant_builder_add (&ret, "{ii}", i1 * 2, i2 * 3);
     519        g_variant_unref (v);
     520        g_variant_builder_close (&ret);
     521  
     522        g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{uu}"));
     523        v = g_variant_get_child_value (parameters, 5);
     524        g_variant_iter_init (&iter, v);
     525        while (g_variant_iter_loop (&iter, "uu", &u1, &u2))
     526          g_variant_builder_add (&ret, "{uu}", u1 * 2, u2 * 3);
     527        g_variant_unref (v);
     528        g_variant_builder_close (&ret);
     529  
     530        g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{xx}"));
     531        v = g_variant_get_child_value (parameters, 6);
     532        g_variant_iter_init (&iter, v);
     533        while (g_variant_iter_loop (&iter, "xx", &x1, &x2))
     534          g_variant_builder_add (&ret, "{xx}", x1 + 2, x2  + 1);
     535        g_variant_unref (v);
     536        g_variant_builder_close (&ret);
     537  
     538        g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{tt}"));
     539        v = g_variant_get_child_value (parameters, 7);
     540        g_variant_iter_init (&iter, v);
     541        while (g_variant_iter_loop (&iter, "tt", &t1, &t2))
     542          g_variant_builder_add (&ret, "{tt}", t1 + 2, t2  + 1);
     543        g_variant_unref (v);
     544        g_variant_builder_close (&ret);
     545  
     546        g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{dd}"));
     547        v = g_variant_get_child_value (parameters, 8);
     548        g_variant_iter_init (&iter, v);
     549        while (g_variant_iter_loop (&iter, "dd", &d1, &d2))
     550          g_variant_builder_add (&ret, "{dd}", d1 + 2.5, d2  + 5.0);
     551        g_variant_unref (v);
     552        g_variant_builder_close (&ret);
     553  
     554        g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{ss}"));
     555        v = g_variant_get_child_value (parameters, 9);
     556        g_variant_iter_init (&iter, v);
     557        while (g_variant_iter_loop (&iter, "ss", &s1, &s2))
     558          {
     559            gchar *tmp1, *tmp2;
     560            tmp1 = g_strconcat (s1, "mod", NULL);
     561            tmp2 = g_strconcat (s2, s2, NULL);
     562            g_variant_builder_add (&ret, "{ss}", tmp1, tmp2);
     563            g_free (tmp1);
     564            g_free (tmp2);
     565          }
     566        g_variant_unref (v);
     567        g_variant_builder_close (&ret);
     568  
     569        g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{oo}"));
     570        v = g_variant_get_child_value (parameters, 10);
     571        g_variant_iter_init (&iter, v);
     572        while (g_variant_iter_loop (&iter, "oo", &s1, &s2))
     573          {
     574            gchar *tmp1, *tmp2;
     575            tmp1 = g_strconcat (s1, "/mod", NULL);
     576            tmp2 = g_strconcat (s2, "/mod2", NULL);
     577            g_variant_builder_add (&ret, "{oo}", tmp1, tmp2);
     578            g_free (tmp1);
     579            g_free (tmp2);
     580          }
     581        g_variant_unref (v);
     582        g_variant_builder_close (&ret);
     583  
     584        g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{gg}"));
     585        v = g_variant_get_child_value (parameters, 11);
     586        g_variant_iter_init (&iter, v);
     587        while (g_variant_iter_loop (&iter, "gg", &s1, &s2))
     588          {
     589            gchar *tmp1, *tmp2;
     590            tmp1 = g_strconcat (s1, "assgit", NULL);
     591            tmp2 = g_strconcat (s2, s2, NULL);
     592            g_variant_builder_add (&ret, "{gg}", tmp1, tmp2);
     593            g_free (tmp1);
     594            g_free (tmp2);
     595          }
     596        g_variant_unref (v);
     597        g_variant_builder_close (&ret);
     598  
     599        g_dbus_method_invocation_return_value (invocation,
     600                                               g_variant_builder_end (&ret));
     601      }
     602    else if (g_strcmp0 (method_name, "TestStructureTypes") == 0)
     603      {
     604        gint x, y, x1, y1;
     605        const gchar *desc;
     606        GVariantIter *iter1, *iter2;
     607        gchar *desc_ret;
     608        GVariantBuilder ret1, ret2;
     609        GVariantIter *iter;
     610        GVariant *v;
     611        gchar *s1, *s2;
     612  
     613        g_variant_get (parameters, "((ii)(&s(ii)aya{ss}))",
     614                       &x, &y, &desc, &x1, &y1, &iter1, &iter2);
     615  
     616        desc_ret = g_strconcat (desc, "... in bed!", NULL);
     617  
     618        g_variant_builder_init (&ret1, G_VARIANT_TYPE ("ay"));
     619        iter = g_variant_iter_copy (iter1);
     620        while (g_variant_iter_loop (iter1, "y", &v))
     621          g_variant_builder_add (&ret1, "y", v);
     622        while (g_variant_iter_loop (iter, "y", &v))
     623          g_variant_builder_add (&ret1, "y", v);
     624        g_variant_iter_free (iter);
     625        g_variant_iter_free (iter1);
     626  
     627        g_variant_builder_init (&ret2, G_VARIANT_TYPE ("a{ss}"));
     628        while (g_variant_iter_loop (iter1, "ss", &s1, &s2))
     629          {
     630            gchar *tmp;
     631            tmp = g_strconcat (s2, " ... in bed!", NULL);
     632            g_variant_builder_add (&ret1, "{ss}", s1, tmp);
     633            g_free (tmp);
     634          }
     635        g_variant_iter_free (iter2);
     636  
     637        g_dbus_method_invocation_return_value (invocation,
     638             g_variant_new ("((ii)(&s(ii)aya{ss}))",
     639                            x + 1, y + 1, desc_ret, x1 + 2, y1 + 2,
     640                            &ret1, &ret2));
     641  
     642        g_free (desc_ret);
     643      }
     644    else if (g_strcmp0 (method_name, "TestVariant") == 0)
     645      {
     646        GVariant *v;
     647        gboolean modify;
     648        GVariant *ret;
     649  
     650        g_variant_get (parameters, "(vb)", &v, &modify);
     651  
     652        /* FIXME handle more cases */
     653        if (modify)
     654          {
     655            if (g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN))
     656              {
     657                ret = g_variant_new_boolean (FALSE);
     658              }
     659            else if (g_variant_is_of_type (v, G_VARIANT_TYPE_TUPLE))
     660              {
     661                ret = g_variant_new ("(si)", "other struct", 100);
     662              }
     663            else
     664              g_assert_not_reached ();
     665          }
     666        else
     667          ret = v;
     668  
     669        g_dbus_method_invocation_return_value (invocation, ret);
     670        g_variant_unref (v);
     671      }
     672    else if (g_strcmp0 (method_name, "TestComplexArrays") == 0)
     673      {
     674        /* FIXME */
     675        g_dbus_method_invocation_return_value (invocation, parameters);
     676      }
     677    else if (g_strcmp0 (method_name, "TestComplexHashTables") == 0)
     678      {
     679        /* FIXME */
     680        g_dbus_method_invocation_return_value (invocation, parameters);
     681      }
     682    else if (g_strcmp0 (method_name, "FrobSetProperty") == 0)
     683      {
     684        gchar *name;
     685        GVariant *value;
     686        g_variant_get (parameters, "(sv)", &name, &value);
     687        g_hash_table_replace (properties, name, value);
     688        g_dbus_connection_emit_signal (connection,
     689                                       NULL,
     690                                       "/com/example/TestObject",
     691                                       "org.freedesktop.DBus.Properties",
     692                                       "PropertiesChanged",
     693                                       g_variant_new_parsed ("('com.example.Frob', [{%s, %v}], @as [])", name, value),
     694                                       NULL);
     695        g_dbus_method_invocation_return_value (invocation, NULL);
     696      }
     697    else if (g_strcmp0 (method_name, "FrobInvalidateProperty") == 0)
     698      {
     699        const gchar *value;
     700        g_variant_get (parameters, "(&s)", &value);
     701        g_hash_table_replace (properties, g_strdup ("PropertyThatWillBeInvalidated"), g_variant_ref_sink (g_variant_new_string (value)));
     702  
     703        g_dbus_connection_emit_signal (connection,
     704                                       NULL,
     705                                       "/com/example/TestObject",
     706                                       "org.freedesktop.DBus.Properties",
     707                                       "PropertiesChanged",
     708                                       g_variant_new_parsed ("('com.example.Frob', @a{sv} [], ['PropertyThatWillBeInvalidated'])"),
     709                                       NULL);
     710        g_dbus_method_invocation_return_value (invocation, NULL);
     711      }
     712    else if (g_strcmp0 (method_name, "EmitSignal") == 0)
     713      {
     714        const gchar *str;
     715        const gchar *path;
     716        gchar *str_ret;
     717        gchar *path_ret;
     718        g_variant_get (parameters, "(&s&o)", &str, &path);
     719        str_ret = g_strconcat (str, " .. in bed!", NULL);
     720        path_ret = g_strconcat (path, "/in/bed", NULL);
     721        g_dbus_connection_emit_signal (connection,
     722                                       NULL,
     723                                       "/com/example/TestObject",
     724                                       "com.example.Frob",
     725                                       "TestSignal",
     726                                       g_variant_new_parsed ("(%s, %o, <'a variant'>)", str_ret, path_ret),
     727                                       NULL);
     728        g_free (str_ret);
     729        g_free (path_ret);
     730        g_dbus_method_invocation_return_value (invocation, NULL);
     731      }
     732    else if (g_strcmp0 (method_name, "EmitSignal2") == 0)
     733      {
     734        g_dbus_connection_emit_signal (connection,
     735                                       NULL,
     736                                       "/com/example/TestObject",
     737                                       "com.example.Frob",
     738                                       "TestSignal2",
     739                                       g_variant_new_parsed ("(42, )"),
     740                                       NULL);
     741        g_dbus_method_invocation_return_value (invocation, NULL);
     742      }
     743    else if (g_strcmp0 (method_name, "Sleep") == 0)
     744      {
     745        gint msec;
     746  
     747        g_variant_get (parameters, "(i)", &msec);
     748  
     749        g_timeout_add ((guint)msec, end_sleep, g_object_ref (invocation));
     750      }
     751    else if (g_strcmp0 (method_name, "Quit") == 0)
     752      {
     753        g_dbus_method_invocation_return_value (invocation, NULL);
     754        g_main_loop_quit (loop);
     755      }
     756  }
     757  
     758  static GVariant *
     759  handle_get_property (GDBusConnection  *connection,
     760                       const gchar      *sender,
     761                       const gchar      *object_path,
     762                       const gchar      *interface_name,
     763                       const gchar      *property_name,
     764                       GError          **error,
     765                       gpointer          user_data)
     766  {
     767    GVariant *ret;
     768  
     769    ret = g_hash_table_lookup (properties, property_name);
     770    if (ret)
     771      {
     772        g_assert (!g_variant_is_floating (ret));
     773        g_variant_ref (ret);
     774      }
     775    else
     776      {
     777        g_set_error (error,
     778                     G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
     779                     "no such property: %s", property_name);
     780      }
     781  
     782    return ret;
     783  }
     784  
     785  static gboolean
     786  handle_set_property (GDBusConnection  *connection,
     787                       const gchar      *sender,
     788                       const gchar      *object_path,
     789                       const gchar      *interface_name,
     790                       const gchar      *property_name,
     791                       GVariant         *value,
     792                       GError          **error,
     793                       gpointer          user_data)
     794  {
     795    g_set_error (error,
     796                 G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
     797                 "SetProperty not implemented");
     798    return FALSE;
     799  }
     800  
     801  static const GDBusInterfaceVTable interface_vtable =
     802  {
     803    handle_method_call,
     804    handle_get_property,
     805    handle_set_property,
     806    { 0 }
     807  };
     808  
     809  static void
     810  on_bus_acquired (GDBusConnection *connection,
     811                   const gchar     *name,
     812                   gpointer         user_data)
     813  {
     814    guint id;
     815  
     816    id = g_dbus_connection_register_object (connection,
     817                                            "/com/example/TestObject",
     818                                            introspection_data->interfaces[0],
     819                                            &interface_vtable,
     820                                            NULL,
     821                                            NULL,
     822                                            NULL);
     823    g_assert (id > 0);
     824  }
     825  
     826  static void
     827  on_name_acquired (GDBusConnection *connection,
     828                    const gchar     *name,
     829                    gpointer         user_data)
     830  {
     831  }
     832  
     833  static void
     834  on_name_lost (GDBusConnection *connection,
     835                const gchar     *name,
     836                gpointer         user_data)
     837  {
     838    exit (1);
     839  }
     840  
     841  int
     842  main (int argc, char *argv[])
     843  {
     844    guint owner_id;
     845  
     846    g_log_writer_default_set_use_stderr (TRUE);
     847  
     848    introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
     849    properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref);
     850    g_hash_table_insert (properties, g_strdup ("y"), g_variant_ref_sink (g_variant_new_byte (1)));
     851    g_hash_table_insert (properties, g_strdup ("b"), g_variant_ref_sink (g_variant_new_boolean (TRUE)));
     852    g_hash_table_insert (properties, g_strdup ("n"), g_variant_ref_sink (g_variant_new_int16 (2)));
     853    g_hash_table_insert (properties, g_strdup ("q"), g_variant_ref_sink (g_variant_new_uint16 (3)));
     854    g_hash_table_insert (properties, g_strdup ("i"), g_variant_ref_sink (g_variant_new_int32 (4)));
     855    g_hash_table_insert (properties, g_strdup ("u"), g_variant_ref_sink (g_variant_new_uint32 (5)));
     856    g_hash_table_insert (properties, g_strdup ("x"), g_variant_ref_sink (g_variant_new_int64 (6)));
     857    g_hash_table_insert (properties, g_strdup ("t"), g_variant_ref_sink (g_variant_new_uint64 (7)));
     858    g_hash_table_insert (properties, g_strdup ("d"), g_variant_ref_sink (g_variant_new_double (7.5)));
     859    g_hash_table_insert (properties, g_strdup ("s"), g_variant_ref_sink (g_variant_new_string ("a string")));
     860    g_hash_table_insert (properties, g_strdup ("o"), g_variant_ref_sink (g_variant_new_object_path ("/some/path")));
     861    g_hash_table_insert (properties, g_strdup ("ay"), g_variant_ref_sink (g_variant_new_parsed ("[@y 1, @y 11]")));
     862    g_hash_table_insert (properties, g_strdup ("ab"), g_variant_ref_sink (g_variant_new_parsed ("[true, false]")));
     863    g_hash_table_insert (properties, g_strdup ("an"), g_variant_ref_sink (g_variant_new_parsed ("[@n 2, @n 12]")));
     864    g_hash_table_insert (properties, g_strdup ("aq"), g_variant_ref_sink (g_variant_new_parsed ("[@q 3, @q 13]")));
     865    g_hash_table_insert (properties, g_strdup ("ai"), g_variant_ref_sink (g_variant_new_parsed ("[@i 4, @i 14]")));
     866    g_hash_table_insert (properties, g_strdup ("au"), g_variant_ref_sink (g_variant_new_parsed ("[@u 5, @u 15]")));
     867    g_hash_table_insert (properties, g_strdup ("ax"), g_variant_ref_sink (g_variant_new_parsed ("[@x 6, @x 16]")));
     868    g_hash_table_insert (properties, g_strdup ("at"), g_variant_ref_sink (g_variant_new_parsed ("[@t 7, @t 17]")));
     869    g_hash_table_insert (properties, g_strdup ("ad"), g_variant_ref_sink (g_variant_new_parsed ("[7.5, 17.5]")));
     870    g_hash_table_insert (properties, g_strdup ("as"), g_variant_ref_sink (g_variant_new_parsed ("['a string', 'another string']")));
     871    g_hash_table_insert (properties, g_strdup ("ao"), g_variant_ref_sink (g_variant_new_parsed ("[@o '/some/path', @o '/another/path']")));
     872    g_hash_table_insert (properties, g_strdup ("foo"), g_variant_ref_sink (g_variant_new_string ("a frobbed string")));
     873    g_hash_table_insert (properties, g_strdup ("PropertyThatWillBeInvalidated"), g_variant_ref_sink (g_variant_new_string ("InitialValue")));
     874  
     875    owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
     876                               "com.example.TestService",
     877                               G_BUS_NAME_OWNER_FLAGS_NONE,
     878                               on_bus_acquired,
     879                               on_name_acquired,
     880                               on_name_lost,
     881                               NULL,
     882                               NULL);
     883  
     884    loop = g_main_loop_new (NULL, FALSE);
     885    g_main_loop_run (loop);
     886  
     887    g_bus_unown_name (owner_id);
     888  
     889    g_dbus_node_info_unref (introspection_data);
     890    g_hash_table_unref (properties);
     891  
     892    return 0;
     893  }