From fafc38bb45db8031fc6f252e86df86dc585fefc9 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 17 Sep 2003 13:56:29 +0000 Subject: must cvs add... --- glib/dbus-gutils.c | 96 +++++++++++++ glib/dbus-gutils.h | 40 ++++++ tools/dbus-tree-view.c | 373 +++++++++++++++++++++++++++++++++++++++++++++++++ tools/dbus-tree-view.h | 36 +++++ tools/dbus-viewer.c | 320 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 865 insertions(+) create mode 100644 glib/dbus-gutils.c create mode 100644 glib/dbus-gutils.h create mode 100644 tools/dbus-tree-view.c create mode 100644 tools/dbus-tree-view.h create mode 100644 tools/dbus-viewer.c diff --git a/glib/dbus-gutils.c b/glib/dbus-gutils.c new file mode 100644 index 00000000..e99286f8 --- /dev/null +++ b/glib/dbus-gutils.c @@ -0,0 +1,96 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gutils.c Utils shared between convenience lib and installed lib + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "dbus-gutils.h" +#include "dbus-gtest.h" +#include + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +char** +_dbus_gutils_split_path (const char *path) +{ + int len; + char **split; + int n_components; + int i, j, comp; + + len = strlen (path); + + n_components = 0; + i = 0; + while (i < len) + { + if (path[i] == '/') + n_components += 1; + ++i; + } + + split = g_new0 (char*, n_components + 1); + + comp = 0; + i = 0; + while (i < len) + { + if (path[i] == '/') + ++i; + j = i; + + while (j < len && path[j] != '/') + ++j; + + /* Now [i, j) is the path component */ + g_assert (i < j); + g_assert (path[i] != '/'); + g_assert (j == len || path[j] == '/'); + + split[comp] = g_strndup (&path[i], j - i + 1); + + split[comp][j-i] = '\0'; + + ++comp; + i = j; + } + g_assert (i == len); + + return split; +} + +#ifdef DBUS_BUILD_TESTS + +/** + * @ingroup DBusGLibInternals + * Unit test for GLib utils internals + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_gutils_test (const char *test_data_dir) +{ + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/glib/dbus-gutils.h b/glib/dbus-gutils.h new file mode 100644 index 00000000..af7cee45 --- /dev/null +++ b/glib/dbus-gutils.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gutils.h Utils shared between convenience lib and installed lib + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef DBUS_GLIB_UTILS_H +#define DBUS_GLIB_UTILS_H + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#include +#include + +G_BEGIN_DECLS + +char** _dbus_gutils_split_path (const char *path); + +G_END_DECLS + +#endif /* DBUS_GLIB_UTILS_H */ + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/tools/dbus-tree-view.c b/tools/dbus-tree-view.c new file mode 100644 index 00000000..863ad1e0 --- /dev/null +++ b/tools/dbus-tree-view.c @@ -0,0 +1,373 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-tree-view.c GtkTreeView for a D-BUS interface description + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include "dbus-tree-view.h" + +#include +#define _(x) dgettext (GETTEXT_PACKAGE, x) +#define N_(x) x + +enum +{ + MODEL_COLUMN_INFO, + + MODEL_COLUMN_LAST +}; + +enum +{ + VIEW_COLUMN_NAME, + + VIEW_COLUMN_LAST +}; + +/* We stuff the node tree into a GtkTreeStore, rather + * than bothering to write a custom model + */ +static GtkTreeModel* +model_new (void) +{ + GtkTreeModel *model; + GtkTreeStore *store; + + store = gtk_tree_store_new (MODEL_COLUMN_LAST, + G_TYPE_POINTER); + /* FIXME, BASE_INFO_TYPE doesn't work right (crashes), + * G_TYPE_POINTER has a memleak. BASE_INFO_TYPE problem maybe just a + * bad GTK build on my laptop. + */ + /* BASE_INFO_TYPE); */ + + model = GTK_TREE_MODEL (store); + + return model; +} + +static void set_info (GtkTreeModel *model, + GtkTreeIter *root, + BaseInfo *info); + +static void +append_child_list (GtkTreeModel *model, + GtkTreeIter *parent, + GSList *children) +{ + GSList *tmp; + GtkTreeStore *store; + + store = GTK_TREE_STORE (model); + + /* parent may be NULL for root */ + + tmp = children; + while (tmp != NULL) + { + GtkTreeIter iter; + + gtk_tree_store_append (store, &iter, parent); + + set_info (model, &iter, tmp->data); + + tmp = tmp->next; + } +} + +static void +set_info (GtkTreeModel *model, + GtkTreeIter *root, + BaseInfo *info) +{ + GtkTreeStore *store; + GtkTreeIter child; + + store = GTK_TREE_STORE (model); + + /* Remeber that root is NULL for "/" path */ + + /* Clear existing children */ + while (gtk_tree_model_iter_children (model, &child, root)) + gtk_tree_store_remove (store, &child); + + /* Set our new value; we simply discard NodeInfo for "/" at the + * moment. + */ + if (root != NULL) + { + base_info_ref (info); /* FIXME once boxed types are working */ + gtk_tree_store_set (store, root, + MODEL_COLUMN_INFO, info, + -1); + } + + /* Fill in new children */ + switch (base_info_get_type (info)) + { + case INFO_TYPE_NODE: + append_child_list (model, root, + node_info_get_interfaces ((NodeInfo*)info)); + append_child_list (model, root, + node_info_get_nodes ((NodeInfo*)info)); + break; + case INFO_TYPE_INTERFACE: + append_child_list (model, root, + interface_info_get_methods ((InterfaceInfo*)info)); + append_child_list (model, root, + interface_info_get_signals ((InterfaceInfo*)info)); + break; + case INFO_TYPE_METHOD: + append_child_list (model, root, + method_info_get_args ((MethodInfo*)info)); + break; + case INFO_TYPE_SIGNAL: + append_child_list (model, root, + signal_info_get_args ((SignalInfo*)info)); + break; + case INFO_TYPE_ARG: + /* no children */ + break; + } +} + +static void +ensure_tree_node (GtkTreeModel *model, + const char **path, + GtkTreeIter *iter) +{ + GtkTreeStore *store; + int i; + GtkTreeIter child; + GtkTreeIter *parent; + GtkTreeIter prev; + + store = GTK_TREE_STORE (model); + + /* The path[0] == NULL case for path "/" can't happen since no tree + * node is created for that + */ + g_assert (path[0] != NULL); + + parent = NULL; + + i = 0; + while (path[i] != NULL) + { + gboolean found; + + found = FALSE; + + if (gtk_tree_model_iter_children (model, &child, parent)) + { + /* Scan for the right path */ + do + { + BaseInfo *info; + + info = NULL; + gtk_tree_model_get (model, &child, + MODEL_COLUMN_INFO, &info, + -1); + + if (info != NULL && + base_info_get_type (info) == INFO_TYPE_NODE && + strcmp (base_info_get_name (info), path[i]) == 0) + { + /* Found it */ + found = TRUE; + break; + } + } + while (gtk_tree_model_iter_next (model, &child)); + } + + if (!found) + { + NodeInfo *node; + + node = node_info_new (path[i]); + + gtk_tree_store_append (store, &child, parent); + gtk_tree_store_set (store, &child, + MODEL_COLUMN_INFO, node, + -1); + } + + prev = child; + parent = &prev; + + ++i; + } + + g_assert (parent == &prev); + *iter = prev; +} + +static void +model_update (GtkTreeModel *model, + const char **path, + NodeInfo *node) +{ + GtkTreeStore *store; + + store = GTK_TREE_STORE (model); + + if (path[0] == NULL) + { + /* Setting '/' */ + + set_info (model, NULL, (BaseInfo*) node); + } + else + { + GtkTreeIter iter; + BaseInfo *old; + + /* Be sure we have the parent node */ + ensure_tree_node (model, path, &iter); + + /* Force the canonical relative path name on the node */ + old = NULL; + gtk_tree_model_get (model, &iter, + MODEL_COLUMN_INFO, &old, + -1); + base_info_set_name ((BaseInfo*) node, + base_info_get_name (old)); + + /* Fill in the new children */ + set_info (model, &iter, (BaseInfo*) node); + } +} + +static void +info_set_func_text (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + BaseInfo *info; + GString *str; + + info = NULL; + gtk_tree_model_get (model, iter, + MODEL_COLUMN_INFO, &info, + -1); + + if (info == NULL) + return; + + str = g_string_new (NULL); + + switch (base_info_get_type (info)) + { + case INFO_TYPE_NODE: + g_string_append (str, "path"); + break; + case INFO_TYPE_INTERFACE: + g_string_append (str, "interface"); + break; + case INFO_TYPE_METHOD: + g_string_append (str, "method"); + break; + case INFO_TYPE_SIGNAL: + g_string_append (str, "signal"); + break; + case INFO_TYPE_ARG: + g_string_append (str, "arg"); + break; + } + + g_string_append (str, " "); + g_string_append (str, base_info_get_name (info)); + + g_object_set (GTK_CELL_RENDERER (cell), + "markup", str->str, + NULL); + + g_string_free (str, TRUE); + + /* base_info_unref (info); */ +} + +GtkWidget* +dbus_tree_view_new (void) +{ + GtkWidget *treeview; + GtkCellRenderer *cell_renderer; + GtkTreeViewColumn *column; + + treeview = gtk_tree_view_new (); + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (column, _("Name")); + + cell_renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, + cell_renderer, + TRUE); + gtk_tree_view_column_set_cell_data_func (column, cell_renderer, + info_set_func_text, NULL, NULL); + + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), + column); + + return treeview; +} + +void +dbus_tree_view_update (GtkTreeView *view, + const char **path, + NodeInfo *node) +{ + GtkTreeModel *model; + + g_return_if_fail (GTK_IS_TREE_VIEW (view)); + + model = gtk_tree_view_get_model (view); + + if (model == NULL) + { + model = model_new (); + model_update (model, path, node); + gtk_tree_view_set_model (view, model); + g_object_unref (G_OBJECT (model)); + } + else + { + model_update (model, path, node); + } +} + +void +dbus_tree_view_clear (GtkTreeView *view) +{ + GtkTreeModel *model; + + g_return_if_fail (GTK_IS_TREE_VIEW (view)); + + model = gtk_tree_view_get_model (view); + + if (model != NULL) + gtk_tree_store_clear (GTK_TREE_STORE (model)); +} + diff --git a/tools/dbus-tree-view.h b/tools/dbus-tree-view.h new file mode 100644 index 00000000..3377ac88 --- /dev/null +++ b/tools/dbus-tree-view.h @@ -0,0 +1,36 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-tree-view.h GtkTreeView for a D-BUS interface description + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef DBUS_TREE_VIEW_H +#define DBUS_TREE_VIEW_H + +#include +#include +#include + +GtkWidget* dbus_tree_view_new (void); +void dbus_tree_view_update (GtkTreeView *view, + const char **path, + NodeInfo *info); +void dbus_tree_view_clear (GtkTreeView *view); + +#endif /* DBUS_TREE_VIEW_H */ diff --git a/tools/dbus-viewer.c b/tools/dbus-viewer.c new file mode 100644 index 00000000..561a65af --- /dev/null +++ b/tools/dbus-viewer.c @@ -0,0 +1,320 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-viewer.c Graphical D-BUS frontend utility + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include +#include +#include +#include +#include "dbus-tree-view.h" +#include +#include + +#include +#define _(x) dgettext (GETTEXT_PACKAGE, x) +#define N_(x) x + +typedef struct +{ + int refcount; + char *name; + +} ServiceData; + +static ServiceData* +service_data_new (const char *name) +{ + ServiceData *sd; + + sd = g_new0 (ServiceData, 1); + + sd->refcount = 1; + sd->name = g_strdup (name); + + return sd; +} + +static void +service_data_ref (ServiceData *sd) +{ + sd->refcount += 1; +} + +static void +service_data_unref (ServiceData *sd) +{ + sd->refcount -= 1; + if (sd->refcount == 0) + { + g_free (sd->name); + g_free (sd); + } +} + +typedef struct +{ + GtkWidget *window; + GtkWidget *treeview; + GtkWidget *service_menu; + + GSList *services; + +} TreeWindow; + +static void +window_closed_callback (GtkWidget *window, + TreeWindow *w) +{ + g_assert (window == w->window); + w->window = NULL; + gtk_main_quit (); +} + +static TreeWindow* +tree_window_new (void) +{ + TreeWindow *w; + GtkWidget *sw; + GtkWidget *vbox; + GtkWidget *hbox; + + /* Should use glade, blah */ + + w = g_new0 (TreeWindow, 1); + w->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_window_set_title (GTK_WINDOW (w->window), "D-BUS Viewer"); + gtk_window_set_default_size (GTK_WINDOW (w->window), 400, 500); + + g_signal_connect (w->window, "destroy", G_CALLBACK (window_closed_callback), + w); + gtk_container_set_border_width (GTK_CONTAINER (w->window), 6); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (w->window), vbox); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (vbox), hbox); + + /* Create tree view */ + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + gtk_box_pack_start (GTK_BOX (hbox), sw, TRUE, TRUE, 0); + + w->treeview = dbus_tree_view_new (); + + gtk_container_add (GTK_CONTAINER (sw), w->treeview); + + /* Create services option menu */ + + + + /* Show everything */ + gtk_widget_show_all (w->window); + + return w; +} + +static void +show_error_dialog (GtkWindow *transient_parent, + GtkWidget **weak_ptr, + const char *message_format, + ...) +{ + char *message; + va_list args; + + if (message_format) + { + va_start (args, message_format); + message = g_strdup_vprintf (message_format, args); + va_end (args); + } + else + message = NULL; + + if (weak_ptr == NULL || *weak_ptr == NULL) + { + GtkWidget *dialog; + dialog = gtk_message_dialog_new (transient_parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + message); + + g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (gtk_widget_destroy), NULL); + + if (weak_ptr != NULL) + { + *weak_ptr = dialog; + g_object_add_weak_pointer (G_OBJECT (dialog), (void**)weak_ptr); + } + + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + + gtk_widget_show_all (dialog); + } + else + { + g_return_if_fail (GTK_IS_MESSAGE_DIALOG (*weak_ptr)); + + gtk_label_set_text (GTK_LABEL (GTK_MESSAGE_DIALOG (*weak_ptr)->label), message); + + gtk_window_present (GTK_WINDOW (*weak_ptr)); + } +} + +static void +usage (int ecode) +{ + fprintf (stderr, "dbus-viewer [--version] [--help]\n"); + exit (ecode); +} + +static void +version (void) +{ + printf ("D-BUS Message Bus Viewer %s\n" + "Copyright (C) 2003 Red Hat, Inc.\n" + "This is free software; see the source for copying conditions.\n" + "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", + VERSION); + exit (0); +} + +int +main (int argc, char **argv) +{ + const char *prev_arg; + int i; + GSList *files; + gboolean end_of_args; + GSList *tmp; + + bindtextdomain (GETTEXT_PACKAGE, DBUS_LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + gtk_init (&argc, &argv); + + end_of_args = FALSE; + files = NULL; + prev_arg = NULL; + i = 1; + while (i < argc) + { + const char *arg = argv[i]; + + if (!end_of_args) + { + if (strcmp (arg, "--help") == 0 || + strcmp (arg, "-h") == 0 || + strcmp (arg, "-?") == 0) + usage (0); + else if (strcmp (arg, "--version") == 0) + version (); + else if (arg[0] == '-' && + arg[1] == '-' && + arg[2] == '\0') + end_of_args = TRUE; + else if (arg[0] == '-') + { + usage (1); + } + else + { + files = g_slist_prepend (files, (char*) arg); + } + } + else + files = g_slist_prepend (files, (char*) arg); + + prev_arg = arg; + + ++i; + } + + files = g_slist_reverse (files); + + tmp = files; + while (tmp != NULL) + { + NodeInfo *node; + GError *error; + const char *filename; + + filename = tmp->data; + + error = NULL; + node = description_load_from_file (filename, + &error); + if (node == NULL) + { + g_assert (error != NULL); + show_error_dialog (NULL, NULL, + _("Unable to load \"%s\": %s\n"), + filename, error->message); + g_error_free (error); + } + else + { + TreeWindow *w; + char **path; + const char *name; + + name = node_info_get_name (node); + if (name == NULL || + name[0] != '/') + { + g_printerr (_("Assuming root node of \"%s\" is at path /, since no absolute path is specified"), filename); + name = "/"; + } + + path = _dbus_gutils_split_path (name); + + w = tree_window_new (); + dbus_tree_view_update (GTK_TREE_VIEW (w->treeview), + (const char**) path, + node); + node_info_unref (node); + + g_strfreev (path); + } + + tmp = tmp->next; + } + + gtk_main (); + + return 0; +} + + + + + + -- cgit v1.2.1