Main Page | Modules | Data Structures | Directories | File List | Data Fields | Related Pages

statemachine-client.c

00001 #include <dbus/dbus-glib.h>
00002 #include <stdio.h>
00003 #include <stdlib.h>
00004 #include <string.h>
00005 #include <gtk/gtk.h>
00006 #include <glib/gi18n.h>
00007 #include "sm-marshal.h"
00008 
00009 static void lose (const char *fmt, ...) G_GNUC_NORETURN G_GNUC_PRINTF (1, 2);
00010 static void lose_gerror (const char *prefix, GError *error) G_GNUC_NORETURN;
00011 
00012 static void
00013 lose (const char *str, ...)
00014 {
00015   va_list args;
00016   GtkWidget *dialog;
00017   char *text;
00018 
00019   va_start (args, str);
00020 
00021   text = g_strdup_vprintf (str, args);
00022 
00023   va_end (args);
00024 
00025   dialog = gtk_message_dialog_new (NULL,
00026                                    GTK_DIALOG_DESTROY_WITH_PARENT,
00027                                    GTK_MESSAGE_ERROR,
00028                                    GTK_BUTTONS_CLOSE,
00029                                    "%s",
00030                                    text);
00031   gtk_dialog_run (GTK_DIALOG (dialog));
00032 
00033   g_free (text);
00034 
00035   exit (1);
00036 }
00037 
00038 static void
00039 lose_gerror (const char *prefix, GError *error) 
00040 {
00041   GtkWidget *dialog;
00042 
00043   dialog = gtk_message_dialog_new (NULL,
00044                                    GTK_DIALOG_DESTROY_WITH_PARENT,
00045                                    GTK_MESSAGE_ERROR,
00046                                    GTK_BUTTONS_CLOSE,
00047                                    "%s",
00048                                    prefix);
00049   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
00050                                             "%s",
00051                                             error->message);
00052 
00053   gtk_dialog_run (GTK_DIALOG (dialog));
00054 
00055   exit (1);
00056 }
00057 
00058 typedef struct
00059 {
00060   char *name;
00061   char *state;
00062   gdouble progress;
00063   DBusGProxy *proxy;
00064   DBusGProxyCall *get_progress_call;
00065 } MachineInfo;
00066 
00067 typedef struct
00068 {
00069   GtkWindow *window;
00070   GtkWidget *view;
00071   GtkTreeModel *store;
00072 
00073   DBusGConnection *bus;
00074   DBusGProxy *server_proxy;
00075 
00076   GSList *pending_creation_calls;
00077   DBusGProxyCall *get_machines_call;
00078 } ClientState;
00079 
00080 static gboolean
00081 proxy_to_iter (GtkTreeModel *model, DBusGProxy *proxy, GtkTreeIter *iter)
00082 {
00083   if (!gtk_tree_model_get_iter_first (model, iter))
00084     return FALSE;
00085   do {
00086     MachineInfo *info;
00087     gtk_tree_model_get (model, iter, 0, &info, -1);
00088     if (info->proxy == proxy)
00089       return TRUE;
00090   } while (gtk_tree_model_iter_next (model, iter));
00091   return FALSE;
00092 }
00093 
00094 static void
00095 signal_row_change (ClientState *state, GtkTreeIter *iter)
00096 {
00097   GtkTreePath *path;
00098   path = gtk_tree_model_get_path (state->store, iter);
00099   gtk_tree_model_row_changed (state->store, path, iter);
00100   gtk_tree_path_free (path);
00101 }
00102 
00103 static void
00104 get_machine_info_cb (DBusGProxy *proxy,
00105                      DBusGProxyCall *call,
00106                      gpointer data)
00107 {
00108   GtkTreeIter iter;
00109   ClientState *state = data;
00110   GError *error = NULL;
00111   char *name, *statename;
00112   MachineInfo *info;
00113 
00114   if (!dbus_g_proxy_end_call (proxy, call, &error,
00115                               G_TYPE_STRING, &name,
00116                               G_TYPE_STRING, &statename,
00117                               G_TYPE_INVALID))
00118     lose_gerror ("Couldn't complete GetInfo", error);
00119 
00120   if (!proxy_to_iter (state->store, proxy, &iter))
00121     g_assert_not_reached ();
00122   
00123   gtk_tree_model_get (state->store, &iter, 0, &info, -1);
00124   g_free (info->name);
00125   info->name = name;
00126   g_free (info->state);
00127   info->state = statename;
00128   signal_row_change (state, &iter);
00129 }
00130 
00131 static void
00132 set_proxy_acquisition_progress (ClientState *state,
00133                                 DBusGProxy *proxy,
00134                                 double progress)
00135 {
00136   MachineInfo *info;
00137   GtkTreeIter iter;
00138 
00139   if (!proxy_to_iter (state->store, proxy, &iter))
00140     g_assert_not_reached ();
00141   gtk_tree_model_get (state->store, &iter, 0, &info, -1);
00142 
00143   /* Ignore machines in unknown state */
00144   if (!info->state)
00145     return;
00146   
00147   if (strcmp (info->state, "Acquired"))
00148     lose ("Got AcquisitionProgress signal in bad state %s",
00149           info->state);
00150 
00151   g_print ("Got acquisition progress change for %p (%s) to %f\n", proxy, info->name ? info->name : "(unknown)", progress);
00152 
00153   info->progress = progress;
00154 
00155   signal_row_change (state, &iter);
00156 }
00157 
00158 static void
00159 proxy_acquisition_changed_cb (DBusGProxy *proxy,
00160                               double progress,
00161                               gpointer user_data)
00162 {
00163   set_proxy_acquisition_progress (user_data, proxy, progress);
00164 }
00165 
00166 static void
00167 get_acquiring_progress_cb (DBusGProxy *proxy,
00168                            DBusGProxyCall *call,
00169                            gpointer user_data)
00170 {
00171   GError *error = NULL;
00172   MachineInfo *info;
00173   GtkTreeIter iter;
00174   ClientState *state = user_data;
00175   gdouble progress;
00176 
00177   if (!proxy_to_iter (state->store, proxy, &iter))
00178     g_assert_not_reached ();
00179   gtk_tree_model_get (state->store, &iter, 0, &info, -1);
00180 
00181   g_assert (info->get_progress_call == call);
00182 
00183   if (!dbus_g_proxy_end_call (proxy, call, &error,
00184                               G_TYPE_DOUBLE, &progress, G_TYPE_INVALID))
00185     lose_gerror ("Failed to complete GetAcquiringProgress call", error);
00186   info->get_progress_call = NULL;
00187 
00188   set_proxy_acquisition_progress (state, proxy, progress);
00189 }
00190 
00191 static void
00192 proxy_state_changed_cb (DBusGProxy *proxy,
00193                         const char *statename,
00194                         gpointer user_data)
00195 {
00196   MachineInfo *info;
00197   GtkTreeIter iter;
00198   ClientState *state = user_data;
00199 
00200   if (!proxy_to_iter (state->store, proxy, &iter))
00201     g_assert_not_reached ();
00202   gtk_tree_model_get (state->store, &iter, 0, &info, -1);
00203 
00204   g_print ("Got state change for %p (%s) to %s\n", proxy, info->name ? info->name : "(unknown)", statename);
00205 
00206   g_free (info->state);
00207   info->state = g_strdup (statename);
00208 
00209   if (!strcmp (info->state, "Acquired"))
00210     {
00211       g_print ("Starting GetAcquiringProgress call for %p\n", info->proxy);
00212       if (info->get_progress_call != NULL)
00213         {
00214           dbus_g_proxy_cancel_call (info->proxy, info->get_progress_call);
00215           info->get_progress_call = NULL;
00216         }
00217       info->get_progress_call = 
00218         dbus_g_proxy_begin_call (info->proxy, "GetAcquiringProgress",
00219                                  get_acquiring_progress_cb,
00220                                  state, NULL,
00221                                  G_TYPE_INVALID);
00222     }
00223   else
00224     info->progress = 0.0;
00225 
00226   signal_row_change (state, &iter);
00227 }
00228 
00229 static void
00230 add_machine (ClientState *state,
00231              const char *name,
00232              const char *mstate,             
00233              const char *path)
00234 {
00235   MachineInfo *info;
00236   GtkTreeIter iter;
00237 
00238   info = g_new0 (MachineInfo, 1);
00239   info->name = g_strdup (name);
00240   info->state = g_strdup (mstate);
00241   info->progress = 0.0;
00242 
00243   info->proxy = dbus_g_proxy_new_for_name (state->bus,
00244                                            "com.example.StateServer",
00245                                            path,
00246                                            "com.example.StateMachine");
00247 
00248   if (!info->state)
00249     {
00250       g_print ("Starting GetInfo call for %p\n", info->proxy);
00251       dbus_g_proxy_begin_call (info->proxy, "GetInfo",
00252                                get_machine_info_cb,
00253                                state, NULL,
00254                                G_TYPE_INVALID);
00255     }
00256 
00257   /* Watch for state changes */
00258   dbus_g_proxy_add_signal (info->proxy, "StateChanged",
00259                            G_TYPE_STRING, G_TYPE_INVALID);
00260   
00261   dbus_g_proxy_connect_signal (info->proxy,
00262                                "StateChanged", 
00263                                G_CALLBACK (proxy_state_changed_cb),
00264                                state,
00265                                NULL);
00266 
00267   dbus_g_proxy_add_signal (info->proxy, "AcquisitionProgress",
00268                            G_TYPE_DOUBLE, G_TYPE_INVALID);
00269   
00270   dbus_g_proxy_connect_signal (info->proxy,
00271                                "AcquisitionProgress", 
00272                                G_CALLBACK (proxy_acquisition_changed_cb),
00273                                state,
00274                                NULL);
00275 
00276   gtk_list_store_prepend (GTK_LIST_STORE (state->store), &iter);
00277   gtk_list_store_set (GTK_LIST_STORE (state->store), &iter, 0, info, -1);
00278 
00279 }
00280 
00281 static void
00282 machine_created_cb (DBusGProxy *proxy,
00283                     const char *name,
00284                     const char *path,
00285                     gpointer data)
00286 {
00287   ClientState *state = data;
00288   
00289   add_machine (state, name, NULL, path);
00290 }
00291 
00292 static void
00293 server_destroyed_cb (DBusGProxy *proxy, gpointer data)
00294 {
00295   g_print ("Server terminated!\n");
00296   GtkWidget *dialog;
00297 
00298   dialog = gtk_message_dialog_new (NULL,
00299                                    GTK_DIALOG_DESTROY_WITH_PARENT,
00300                                    GTK_MESSAGE_INFO,
00301                                    GTK_BUTTONS_CLOSE,
00302                                    "State Machine server has exited");
00303 
00304   gtk_dialog_run (GTK_DIALOG (dialog));
00305 
00306   exit (1);
00307 }
00308 
00309 static void
00310 window_destroyed_cb (GtkWidget *window, gpointer data)
00311 {
00312   gtk_main_quit ();
00313 }
00314 
00315 static void
00316 create_machine_completed_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer data)
00317 {
00318   GError *error = NULL;
00319   ClientState *state = data;
00320 
00321   if (!dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID))
00322     {
00323       /* Ignore NameInUse errors */
00324       if (dbus_g_error_has_name (error, "com.example.StateServer.NameInUse"))
00325         ;
00326       else
00327         lose_gerror ("Failed to create new state machine", error);
00328     }
00329   g_print ("machine created successfully\n");
00330   state->pending_creation_calls = g_slist_remove (state->pending_creation_calls, call);
00331 }
00332 
00333 static void
00334 send_create_machine (ClientState *state)
00335 {
00336   DBusGProxyCall *call;
00337   char *name;
00338   gint n_children;
00339 
00340   n_children = gtk_tree_model_iter_n_children (state->store, NULL);
00341   name = g_strdup_printf ("machine%d", n_children);
00342         
00343   g_print ("Invoking CreateMachine(%s)\n", name);
00344   call = dbus_g_proxy_begin_call (state->server_proxy, "CreateMachine",
00345                                   create_machine_completed_cb,
00346                                   state, NULL,
00347                                   G_TYPE_STRING, name, G_TYPE_INVALID);
00348   g_free (name);
00349   state->pending_creation_calls = g_slist_prepend (state->pending_creation_calls, call);
00350 }
00351 
00352 static void
00353 do_a_state_change (ClientState *state)
00354 {
00355   gint index;
00356   GtkTreeIter iter;
00357   gint n_children;
00358   MachineInfo *info;
00359 
00360   n_children = gtk_tree_model_iter_n_children (state->store, NULL);
00361   if (n_children == 0)
00362     {
00363       g_print ("No machines yet, not doing a state switch\n");
00364       return;
00365     }
00366 
00367   index = g_random_int_range (0, n_children);
00368   gtk_tree_model_iter_nth_child (state->store, &iter, NULL, index);
00369   gtk_tree_model_get (state->store, &iter, 0, &info, -1);
00370 
00371   if (!info->state)
00372     {
00373       g_print ("Machine not yet in known state, skipping state switch\n");
00374       return;
00375     }
00376 
00377   if (!strcmp (info->state, "Shutdown"))
00378     {
00379       g_print ("Sending Start request to machine %s\n", info->name);
00380       dbus_g_proxy_call_no_reply (info->proxy, "Start", G_TYPE_INVALID);
00381     }
00382   else if (!strcmp (info->state, "Loading"))
00383     {
00384       
00385       g_print ("Sending Reacquire request to machine %s\n", info->name);
00386       dbus_g_proxy_call_no_reply (info->proxy, "Reacquire", G_TYPE_INVALID);
00387     }
00388   else
00389     {
00390       g_print ("Sending Shutdown request to machine %s\n", info->name);
00391       dbus_g_proxy_call_no_reply (info->proxy, "Shutdown", G_TYPE_INVALID);
00392     }
00393 }
00394 
00395 static gboolean
00396 do_something_random_2 (gpointer data)
00397 {
00398   ClientState *state = data;
00399   do_a_state_change (state);
00400   g_timeout_add (g_random_int_range (2000, 5000), do_something_random_2, state);
00401   return FALSE;
00402 }
00403 
00404 static gboolean
00405 do_something_random (gpointer data)
00406 {
00407   ClientState *state = data;
00408   gint n_children;
00409 
00410   switch (g_random_int_range (0, 3))
00411     {
00412     case 0:
00413       send_create_machine (state);
00414       break;
00415     case 1:
00416     case 2:
00417       do_a_state_change (state);
00418       break;
00419     default:
00420       g_assert_not_reached ();
00421     }
00422       
00423   n_children = gtk_tree_model_iter_n_children (state->store, NULL);
00424   if (n_children >= 5)
00425     {
00426       g_print ("MAX children reached, switching to state changes only\n");
00427       g_timeout_add (g_random_int_range (500, 3000), do_something_random_2, state);
00428     }
00429   else
00430     g_timeout_add (g_random_int_range (500, 3000), do_something_random, state);
00431   return FALSE;
00432 }
00433 
00434 static void 
00435 set_cell_name (GtkTreeViewColumn *tree_column,
00436                GtkCellRenderer   *cell,
00437                GtkTreeModel      *tree_model,
00438                GtkTreeIter       *iter,
00439                gpointer           data)
00440 {
00441   MachineInfo *info;
00442   
00443   gtk_tree_model_get (tree_model, iter, 0, &info, -1);
00444   
00445   g_object_set (cell, "text", info->name ? info->name : "", NULL);
00446 }
00447 
00448 static gint
00449 sort_by_name (GtkTreeModel *model,
00450               GtkTreeIter  *a,
00451               GtkTreeIter  *b,
00452               gpointer      user_data)
00453 {
00454   MachineInfo *info_a, *info_b;
00455 
00456   gtk_tree_model_get (model, a, 0, &info_a, -1);
00457   gtk_tree_model_get (model, b, 0, &info_b, -1);
00458 
00459   return strcmp (info_a->name ? info_a->name : "", 
00460                  info_b ? info_b->name : "");
00461 }
00462 
00463 static void 
00464 set_cell_state (GtkTreeViewColumn *tree_column,
00465                GtkCellRenderer   *cell,
00466                GtkTreeModel      *tree_model,
00467                GtkTreeIter       *iter,
00468                gpointer           data)
00469 {
00470   MachineInfo *info;
00471   
00472   gtk_tree_model_get (tree_model, iter, 0, &info, -1);
00473   
00474   g_object_set (cell, "text", info->state ? info->state : "", NULL);
00475 }
00476 
00477 static gint
00478 sort_by_state (GtkTreeModel *model,
00479                GtkTreeIter  *a,
00480                GtkTreeIter  *b,
00481                gpointer      user_data)
00482 {
00483   MachineInfo *info_a, *info_b;
00484 
00485   gtk_tree_model_get (model, a, 0, &info_a, -1);
00486   gtk_tree_model_get (model, b, 0, &info_b, -1);
00487 
00488   return strcmp (info_a->state ? info_a->state : "", 
00489                  info_b ? info_b->state : "");
00490 }
00491 
00492 static void 
00493 set_cell_progress (GtkTreeViewColumn *tree_column,
00494                    GtkCellRenderer   *cell,
00495                    GtkTreeModel      *tree_model,
00496                    GtkTreeIter       *iter,
00497                    gpointer           data)
00498 {
00499   MachineInfo *info;
00500   
00501   gtk_tree_model_get (tree_model, iter, 0, &info, -1);
00502   
00503   g_object_set (cell, "value", (int) (info->progress * 100), NULL);
00504 }
00505 
00506 static gint
00507 sort_by_progress (GtkTreeModel *model,
00508                   GtkTreeIter  *a,
00509                   GtkTreeIter  *b,
00510                   gpointer      user_data)
00511 {
00512   MachineInfo *info_a, *info_b;
00513 
00514   gtk_tree_model_get (model, a, 0, &info_a, -1);
00515   gtk_tree_model_get (model, b, 0, &info_b, -1);
00516 
00517   return info_a->progress > info_b->progress ? 1 : -1;
00518 }
00519 
00520 static void
00521 get_machines_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer data)
00522 {
00523   GError *error = NULL;
00524   ClientState *state = data;
00525   GPtrArray *objs;
00526   guint i;
00527   GtkWidget *scrolledwin;
00528   GtkTreeViewColumn *col;
00529   GtkCellRenderer *rend;
00530 
00531   g_assert (call == state->get_machines_call);
00532 
00533   if (!dbus_g_proxy_end_call (proxy, call, &error,
00534                               dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
00535                               &objs,
00536                               G_TYPE_INVALID))
00537     lose_gerror ("Failed to get current machine list", error);
00538 
00539   gtk_container_remove (GTK_CONTAINER (state->window),
00540                         gtk_bin_get_child (GTK_BIN (state->window)));
00541 
00542   scrolledwin = gtk_scrolled_window_new (NULL, NULL);
00543   gtk_widget_show (scrolledwin);
00544 
00545   state->store = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_POINTER));
00546   state->view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (state->store));  
00547   gtk_widget_show (state->view);
00548   gtk_container_add (GTK_CONTAINER (scrolledwin), state->view);
00549   gtk_container_add (GTK_CONTAINER (state->window), scrolledwin);
00550 
00551   rend = gtk_cell_renderer_text_new ();
00552   col = gtk_tree_view_column_new_with_attributes (_("Name"), 
00553                                                   rend, 
00554                                                   NULL);
00555   gtk_tree_view_column_set_cell_data_func (col, rend, set_cell_name, NULL, NULL);
00556   gtk_tree_view_column_set_resizable (col, TRUE);
00557   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (state->store), 
00558                                    0, sort_by_name, NULL, NULL);
00559   gtk_tree_view_column_set_sort_column_id (col, 0);
00560   gtk_tree_view_append_column (GTK_TREE_VIEW (state->view), col);
00561 
00562   rend = gtk_cell_renderer_text_new ();
00563   col = gtk_tree_view_column_new_with_attributes (_("State"), 
00564                                                   rend, 
00565                                                   NULL);
00566   gtk_tree_view_column_set_cell_data_func (col, rend, set_cell_state, NULL, NULL);
00567   gtk_tree_view_column_set_resizable (col, TRUE);
00568   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (state->store), 
00569                                    0, sort_by_state, NULL, NULL);
00570   gtk_tree_view_column_set_sort_column_id (col, 0);
00571   gtk_tree_view_append_column (GTK_TREE_VIEW (state->view), col);
00572 
00573   rend = gtk_cell_renderer_progress_new ();
00574   col = gtk_tree_view_column_new_with_attributes (_("Progress"), 
00575                                                   rend, 
00576                                                   NULL);
00577   gtk_tree_view_column_set_cell_data_func (col, rend, set_cell_progress, NULL, NULL);
00578   gtk_tree_view_column_set_resizable (col, TRUE);
00579   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (state->store), 
00580                                    0, sort_by_progress, NULL, NULL);
00581   gtk_tree_view_column_set_sort_column_id (col, 0);
00582   gtk_tree_view_append_column (GTK_TREE_VIEW (state->view), col);
00583   
00584   for (i = 0; i < objs->len; i++)
00585     {
00586       add_machine (state, NULL, NULL, g_ptr_array_index (objs, i));
00587       g_free (g_ptr_array_index (objs, i));
00588     }
00589   g_ptr_array_free (objs, TRUE);
00590 
00591   g_idle_add (do_something_random, state);
00592 }
00593 
00594 int
00595 main (int argc, char **argv)
00596 {
00597   DBusGConnection *bus;
00598   DBusGProxy *server;
00599   GError *error = NULL;
00600   ClientState state;
00601   GtkWidget *label;
00602 
00603   gtk_init (&argc, &argv);
00604 
00605   g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
00606 
00607   state.window = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
00608   gtk_window_set_resizable (GTK_WINDOW (state.window), TRUE);
00609   g_signal_connect (G_OBJECT (state.window), "destroy",
00610                     G_CALLBACK (window_destroyed_cb),
00611                     &state);
00612   gtk_window_set_title (GTK_WINDOW (state.window), _("D-BUS State Machine Demo"));
00613   gtk_window_set_default_size (GTK_WINDOW (state.window), 320, 240);
00614 
00615   label = gtk_label_new ("");
00616   gtk_label_set_markup (GTK_LABEL (label), "<b>Loading...</b>");
00617   gtk_widget_show (label);
00618 
00619   gtk_container_add (GTK_CONTAINER (state.window), label); 
00620 
00621   bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
00622   if (!bus)
00623     lose_gerror ("Couldn't connect to session bus", error);
00624 
00625   state.bus = bus;
00626 
00627   server = dbus_g_proxy_new_for_name_owner (bus,
00628                                             "com.example.StateServer",
00629                                             "/com/example/StateServer",
00630                                             "com.example.StateMachineServer",
00631                                             &error);
00632   if (!server)
00633     lose_gerror ("Couldn't find \"com.example.StateServer\"", error);
00634 
00635   state.server_proxy = server;
00636 
00637   g_signal_connect (server, "destroy",
00638                     G_CALLBACK (server_destroyed_cb),
00639                     &state);
00640 
00641   dbus_g_object_register_marshaller (sm_marshal_VOID__STRING_BOXED,
00642                                      G_TYPE_NONE, G_TYPE_STRING,
00643                                      DBUS_TYPE_G_OBJECT_PATH);
00644 
00645   dbus_g_proxy_add_signal (server, "MachineCreated", G_TYPE_STRING, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
00646 
00647   dbus_g_proxy_connect_signal (server, "MachineCreated",
00648                                G_CALLBACK (machine_created_cb),
00649                                &state, NULL);
00650 
00651   state.get_machines_call = dbus_g_proxy_begin_call (server, "GetMachines",
00652                                                      get_machines_cb, &state, NULL,
00653                                                      G_TYPE_INVALID);
00654   
00655   gtk_widget_show (GTK_WIDGET (state.window));
00656   
00657   gtk_main ();
00658 
00659   g_object_unref (G_OBJECT (server));
00660 
00661   exit(0);
00662 }

Generated on Tue Aug 30 16:35:52 2005 for D-BUS by  doxygen 1.4.3