summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bechtold <thomasbechtold@jpberlin.de>2012-08-04 13:38:50 +0200
committerThomas Bechtold <thomasbechtold@jpberlin.de>2012-09-14 21:18:15 +0200
commitcf4b5a71a1e1fff59b07be4b458f928fb83190c4 (patch)
tree3ec0281e3f78c430802b31e367351db2ed58c7be
parentaa65bf360dc38b1006ca9e1f8d61d32bdf1ce035 (diff)
downloadd-feet-cf4b5a71a1e1fff59b07be4b458f928fb83190c4.tar.gz
Port to pygi and gdbus
* Port from pygtk to pygi * Port from python-dbus to gdbus * restructure code * add (still simple) testsuite https://bugzilla.gnome.org/show_bug.cgi?id=681093
-rw-r--r--.gitignore2
-rw-r--r--AUTHORS2
-rw-r--r--README8
-rw-r--r--TODO10
-rwxr-xr-xd-feet2
-rw-r--r--d-feet.doap11
-rw-r--r--dfeet/DFeetApp.py283
-rw-r--r--dfeet/_introspect_parser.py150
-rw-r--r--dfeet/_ui/__init__.py2
-rw-r--r--dfeet/_ui/addconnectiondialog.py64
-rw-r--r--dfeet/_ui/busbox.py95
-rw-r--r--dfeet/_ui/busnamebox.py65
-rw-r--r--dfeet/_ui/busnameinfobox.py4
-rw-r--r--dfeet/_ui/busnameview.py162
-rw-r--r--dfeet/_ui/executemethoddialog.py158
-rw-r--r--dfeet/_ui/uiloader.py38
-rw-r--r--dfeet/_ui/wnck_utils.py2
-rw-r--r--dfeet/_util.py32
-rw-r--r--dfeet/bus_watch.py215
-rw-r--r--dfeet/dbus_introspector.py477
-rw-r--r--dfeet/dbus_utils.py1
-rw-r--r--dfeet/introspect_data.py678
-rw-r--r--dfeet/introspection.py229
-rw-r--r--dfeet/introspection_helper.py218
-rwxr-xr-xtests/tests.py106
-rwxr-xr-xtests/tests.py~79
-rwxr-xr-xtests/uifile_tests.py33
-rw-r--r--ui/addconnectiondialog.ui63
-rw-r--r--ui/buswatch.ui210
-rw-r--r--ui/default-actiongroup.ui99
-rw-r--r--ui/executedialog.ui430
-rw-r--r--ui/introspection.ui165
-rw-r--r--ui/introspectview.ui118
-rw-r--r--ui/mainwindow.ui189
34 files changed, 2064 insertions, 2336 deletions
diff --git a/.gitignore b/.gitignore
index 0d20b64..a888202 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
*.pyc
+*~
+\#*#
diff --git a/AUTHORS b/AUTHORS
index ba0eae5..71965fc 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2,6 +2,8 @@ John (J5) Palmieri <johnp@redhat.com>
Ray Strode <rstrode@redhat.com>
Marcel Holtmann <marcel@holtmann.org>
Johan Dahlin <johan@gnome.org>
+Thomas Bechtold <thomasbechtold@jpberlin.de>
+
Some code taken and modified from the D-Bus Python project http://dbus.freedesktop.org
Some code taken and modified from the Jokosher Project http://jokosher.org
diff --git a/README b/README
index 8c3bedc..a582bec 100644
--- a/README
+++ b/README
@@ -2,10 +2,10 @@ Welcome to D-Feet (http://live.gnome.org/d-feet)
Requirements:
-D-Bus > 1.0
-D-Bus Python > 0.82.3
-PyGtk
-Python 2.5
+python >= 2.7
+glib >= 2.34
+gobject-introspection
+python-gi
Optional Requriements:
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..86e5a12
--- /dev/null
+++ b/TODO
@@ -0,0 +1,10 @@
+* reimplement the bustab list save/restore stuff
+* Add checkbox in addconnectiondialog.ui to be able to start a
+ peer-to-peer connection
+* Add filter for introspector treeview. Should be possible to filter
+ methods, properties and interfaces
+* Add menu entry to start a service by name
+ (org.freedesktop.DBus.StartServiceByName)
+* Add a list with activateable services
+ (org.freedesktop.DBus.ListActivatableNames)
+
diff --git a/d-feet b/d-feet
index 8e85c5e..cc15057 100755
--- a/d-feet
+++ b/d-feet
@@ -29,8 +29,6 @@ if options.use_local_dirs:
"DFEET_LOCALE_PATH" : "locale/",
"DFEET_HELP_PATH" : "/usr/share/gnome/dfeet/"
}
-
-
else:
ENV_PATHS = {"DFEET_DATA_PATH" : "/usr/share/dfeet/",
"DFEET_IMAGE_PATH" : "/usr/share/dfeet/pixmaps/",
diff --git a/d-feet.doap b/d-feet.doap
index 3252439..1827172 100644
--- a/d-feet.doap
+++ b/d-feet.doap
@@ -7,7 +7,9 @@
<name xml:lang="en">D-Feet</name>
<shortdesc xml:lang="en">D-Bus Debugger</shortdesc>
<homepage rdf:resource="http://live.gnome.org/DFeet" />
-
+ <download-page rdf:resource="http://download.gnome.org/sources/d-feet/" />
+ <bug-database rdf:resource="https://bugzilla.gnome.org/browse.cgi?product=d-feet" />
+
<maintainer>
<foaf:Person>
<foaf:name>John (J5) Palmieri</foaf:name>
@@ -15,4 +17,11 @@
<gnome:userid>johnp</gnome:userid>
</foaf:Person>
</maintainer>
+ <maintainer>
+ <foaf:Person>
+ <foaf:name>Thomas Bechtold</foaf:name>
+ <foaf:mbox rdf:resource="mailto:thomasbechtold@jpberlin.de" />
+ <gnome:userid>toabctl</gnome:userid>
+ </foaf:Person>
+ </maintainer>
</Project>
diff --git a/dfeet/DFeetApp.py b/dfeet/DFeetApp.py
index 6463592..ef407c7 100644
--- a/dfeet/DFeetApp.py
+++ b/dfeet/DFeetApp.py
@@ -1,209 +1,141 @@
+# -*- coding: utf-8 -*-
import os
import sys
-from gi.repository import Gtk
-import _ui
-import _util
-import dbus_introspector
-import introspect_data
+from gi.repository import Gtk, Gio, GObject
-from dbus_introspector import BusWatch
+
+from bus_watch import BusWatch
+from introspection import AddressInfo
from settings import Settings
from _ui.uiloader import UILoader
from _ui.addconnectiondialog import AddConnectionDialog
from _ui.executemethoddialog import ExecuteMethodDialog
+class NotebookTabLabel(Gtk.Box):
+ __gsignals__ = {
+ "close-clicked": (GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, ()),
+ }
+ def __init__(self, label_text):
+ Gtk.Box.__init__(self)
+ self.set_orientation(Gtk.Orientation.HORIZONTAL)
+ self.set_spacing(5)
+ # label
+ label = Gtk.Label(label_text)
+ self.pack_start(label, True, True, 0)
+ # close button
+ button = Gtk.Button()
+ button.set_relief(Gtk.ReliefStyle.NONE)
+ button.set_focus_on_click(False)
+ button.add(Gtk.Image.new_from_stock(Gtk.STOCK_CLOSE, Gtk.IconSize.MENU))
+ button.connect("clicked", self.__button_clicked)
+ self.pack_end(button, False, False, 0)
+ self.show_all()
+
+ def __button_clicked(self, button, data=None):
+ self.emit("close-clicked")
+
+
class DFeetApp:
HISTORY_MAX_SIZE = 10
def __init__(self):
- signal_dict = {'add_session_bus': self.add_session_bus_cb,
- 'add_system_bus': self.add_system_bus_cb,
- 'add_bus_address': self.add_bus_address_cb,
- 'reconnect_current_bus': self.reconnect_current_bus_cb,
- 'execute_method': self.execute_current_method_cb,
- 'quit': self.quit_cb}
-
- self.ICON_SIZE_CLOSE_BUTTON = Gtk.icon_size_register('ICON_SIZE_CLOSE_BUTTON', 14, 14)
+ signal_dict = {
+ 'action_systembus_connect_activate_cb': self.__systembus_connect_cb,
+ 'action_sessionbus_connect_activate_cb': self.__sessionbus_connect_cb,
+ 'action_otherbus_connect_activate_cb': self.__otherbus_connect_cb,
+ 'action_close_activate_cb': self.__close_cb,
+ }
settings = Settings.get_instance()
ui = UILoader(UILoader.UI_MAINWINDOW)
-
self.main_window = ui.get_root_widget()
- self.main_window.set_icon_name('dfeet-icon')
- self.main_window.connect('delete-event', self._quit_dfeet)
+ self.main_window.connect('delete-event', self.__quit_dfeet)
+ self.main_window.set_default_size(int(settings.general['windowwidth']),
+ int(settings.general['windowheight']))
self.notebook = ui.get_widget('display_notebook')
self.notebook.show_all()
+ self.notebook_page_widget = ui.get_widget('box_notebook_page')
- self.execute_method_action = ui.get_widget('execute_method')
- self.reconnect_current_bus_action = ui.get_widget('reconnect_current_bus')
+ #create bus history list and load entries from settings
+ self.__bus_history = []
+ for bus in settings.general['addbus_list']:
+ if bus != '':
+ self.__bus_history.append(bus)
- self.notebook.connect('switch-page', self.switch_tab_cb)
+ ui.connect_signals(signal_dict)
+ self.main_window.show()
- self.main_window.set_default_size(int(settings.general['windowwidth']),
- int(settings.general['windowheight']))
- self._load_tabs(settings)
- self._load_addbus_history(settings)
+ @property
+ def bus_history(self):
+ return self.__bus_history
- self.main_window.show()
- ui.connect_signals(signal_dict)
+ def __systembus_connect_cb(self, action):
+ """ connect to system bus """
+ bw = BusWatch(Gio.BusType.SYSTEM)
+ self.__notebook_append_page(bw.paned_buswatch, "System Bus")
- def _load_tabs(self, settings):
- for bus_name in settings.general['bustabs_list']:
- if bus_name == 'Session Bus':
- self.add_bus(dbus_introspector.SESSION_BUS)
- elif bus_name == 'System Bus':
- self.add_bus(dbus_introspector.SYSTEM_BUS)
- else:
- self.add_bus(address = bus_name)
-
- def _load_addbus_history(self, settings):
- self.add_bus_history = []
- self.combo_addbus_history_model = Gtk.ListStore(str)
- for bus_add in settings.general['addbus_list']:
- if bus_add != '':
- self.add_bus_history.append(bus_add)
-
- def _add_bus_tab(self, bus_watch, position=None):
- name = bus_watch.get_bus_name()
- bus_paned = _ui.BusBox(bus_watch)
- bus_paned.connect('introspectnode-selected',
- self.introspect_node_selected_cb)
- bus_paned.show_all()
- hbox = Gtk.HBox()
- hbox.pack_start(Gtk.Label(name), True, True, 0)
- close_btn = Gtk.Button()
- img = Gtk.Image()
- img.set_from_stock(Gtk.STOCK_CLOSE, self.ICON_SIZE_CLOSE_BUTTON)
- img.show()
- close_btn.set_image(img)
- close_btn.set_relief(Gtk.ReliefStyle.NONE)
- close_btn.connect('clicked', self.close_tab_cb, bus_paned)
- hbox.pack_start(close_btn, False, False, 0)
- hbox.show_all()
-
- if position:
- self.notebook.insert_page(bus_paned, hbox, position)
- self.notebook.set_current_page(position)
- self.notebook.set_tab_reorderable(bus_paned, True)
- else:
- p = self.notebook.append_page(bus_paned, hbox)
- self.notebook.set_current_page(p)
- self.notebook.set_tab_reorderable(bus_paned, True)
-
- def introspect_node_selected_cb(self, widget, node):
- if isinstance(node, introspect_data.Method):
- self.execute_method_action.set_sensitive(True)
- else:
- self.execute_method_action.set_sensitive(False)
-
- def execute_current_method_cb(self, action):
- page = self.notebook.get_current_page()
- if page >= 0:
- busbox = self.notebook.get_nth_page(page)
- node = busbox.get_selected_introspect_node()
- busname = busbox.get_selected_busname()
- dialog = ExecuteMethodDialog(busname, node)
- dialog.run()
-
- def close_tab_cb(self, button, child):
- n = self.notebook.page_num(child)
- if child.get_bus_watch().get_bus_name() not in [u'Session Bus', u'System Bus']:
- child.get_bus_watch().close_bus()
- self.notebook.remove_page(n)
- if self.notebook.get_n_pages() <= 0:
- self.reconnect_current_bus_action.set_sensitive(False)
-
- def switch_tab_cb(self, notebook, page, page_num):
- child = self.notebook.get_nth_page(page_num)
- if child.get_bus_watch().get_bus_name() not in [u'Session Bus', u'System Bus']:
- self.reconnect_current_bus_action.set_sensitive(True)
- else:
- self.reconnect_current_bus_action.set_sensitive(False)
-
- def select_or_add_bus(self, address):
- for i in range(self.notebook.get_n_pages()):
- page = self.notebook.get_nth_page(i)
- tab_label = self.notebook.get_tab_label(page)
- if tab_label.get_children()[0].get_text() == address:
- self.notebook.set_current_page(i)
- break
- else:
- self.add_bus(address=address)
-
- def add_bus(self, bus_type=None, address=None):
- if bus_type == dbus_introspector.SESSION_BUS or bus_type == dbus_introspector.SYSTEM_BUS:
- bus_watch = BusWatch(bus_type)
- self._add_bus_tab(bus_watch)
- else:
- try:
- bus_watch = BusWatch(None, address=address)
- self._add_bus_tab(bus_watch)
- except Exception, e:
- print e
-
- def add_session_bus_cb(self, action):
- self.add_bus(dbus_introspector.SESSION_BUS)
-
- def add_system_bus_cb(self, action):
- self.add_bus(dbus_introspector.SYSTEM_BUS)
-
- def add_bus_address_cb(self, action):
- dialog = AddConnectionDialog(self.main_window)
- self.combo_addbus_history_model.clear()
- # Load combo box history
- for el in self.add_bus_history:
- self.combo_addbus_history_model.append([el])
- dialog.set_model(self.combo_addbus_history_model)
- result = dialog.run()
- if result == 1:
- bus_address = dialog.get_address()
- if bus_address == 'Session Bus':
- self.add_bus(dbus_introspector.SESSION_BUS)
- elif bus_address == 'System Bus':
- self.add_bus(dbus_introspector.SYSTEM_BUS)
- else:
- self.add_bus(address = bus_address)
- # Fill history
- if bus_address in self.add_bus_history:
- self.add_bus_history.remove(bus_address)
- self.add_bus_history.insert(0, bus_address)
- # Truncating history
- if (len(self.add_bus_history) > self.HISTORY_MAX_SIZE):
- self.add_bus_history = self.add_bus_history[0:self.HISTORY_MAX_SIZE]
- dialog.destroy()
-
- def reconnect_current_bus_cb(self, action):
- page = self.notebook.get_current_page()
- if page >= 0:
- child = self.notebook.get_nth_page(page)
- bus_watch = child.get_bus_watch()
+ def __sessionbus_connect_cb(self, action):
+ """ connect to session bus """
+ bw = BusWatch(Gio.BusType.SESSION)
+ self.__notebook_append_page(bw.paned_buswatch, "Session Bus")
- bus_type = bus_watch.get_bus_type()
- bus_address = bus_watch.get_bus_address()
- if bus_type == dbus_introspector.SESSION_BUS or bus_type == dbus_introspector.SYSTEM_BUS:
- pass
+ def __otherbus_connect_cb(self, action):
+ """ connect to other bus """
+ dialog = AddConnectionDialog(self.main_window, self.bus_history)
+ result = dialog.run()
+ if result == Gtk.ResponseType.OK:
+ address = dialog.address
+ if address == 'Session Bus':
+ self.__sessionbus_connect_cb(None)
+ return
+ elif address == 'System Bus':
+ self.__systembus_connect_cb(None)
+ return
else:
- bus_watch.close_bus()
- self.notebook.remove_page(page)
try:
- new_bus_watch = BusWatch(None, address=bus_address)
- self._add_bus_tab(new_bus_watch, page)
+ bw = BusWatch(address)
+ self.__notebook_append_page(bw.paned_buswatch, address)
+ # Fill history
+ if address in self.bus_history:
+ self.bus_history.remove(address)
+ self.bus_history.insert(0, address)
+ # Truncating history
+ if (len(self.bus_history) > self.HISTORY_MAX_SIZE):
+ self.bus_history = self.bus_history[0:self.HISTORY_MAX_SIZE]
except Exception, e:
- print e
+ print "can not connect to '%s': %s" % (address, str(e))
+ dialog.destroy()
+
+
+ def __notebook_append_page(self, widget, text):
+ """ add a page to the notebook """
+ ntl = NotebookTabLabel(text)
+ page_nbr = self.notebook.append_page(widget, ntl)
+ ntl.connect("close-clicked", self.__notebook_page_close_clicked_cb, widget)
+
- def quit_cb(self, action):
+ def __notebook_page_close_clicked_cb(self, button, widget):
+ """ remove a page from the notebook """
+ nbr = self.notebook.page_num(widget)
+ self.notebook.remove_page(nbr)
+
+
+ def __close_cb(self, action):
+ """ quit program """
self._quit_dfeet(self.main_window, None)
- def _quit_dfeet(self, main_window, event):
+
+ def __quit_dfeet(self, main_window, event):
+ """ quit d-feet application and store some settings """
settings = Settings.get_instance()
size = main_window.get_size()
pos = main_window.get_position()
@@ -211,24 +143,17 @@ class DFeetApp:
settings.general['windowwidth'] = size[0]
settings.general['windowheight'] = size[1]
- n = self.notebook.get_n_pages()
- tab_list = []
- for i in xrange(n):
- child = self.notebook.get_nth_page(i)
- bus_watch = child.get_bus_watch()
- tab_list.append(bus_watch.get_bus_name())
-
- self.add_bus_history = self.add_bus_history[0:self.HISTORY_MAX_SIZE]
+ self.bus_history = self.bus_history[0:self.HISTORY_MAX_SIZE]
- settings.general['bustabs_list'] = tab_list
- settings.general['addbus_list'] = self.add_bus_history
-
+ settings.general['addbus_list'] = self.bus_history
settings.write()
-
Gtk.main_quit()
+
def run(self):
+ """ start the application """
Gtk.main()
+
if __name__ == "__main__":
DFeetApp().run()
diff --git a/dfeet/_introspect_parser.py b/dfeet/_introspect_parser.py
deleted file mode 100644
index 0746cba..0000000
--- a/dfeet/_introspect_parser.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# Copyright (C) 2003, 2004, 2005, 2006 Red Hat Inc. <http://www.redhat.com/>
-# Copyright (C) 2003 David Zeuthen
-# Copyright (C) 2004 Rob Taylor
-# Copyright (C) 2005, 2006 Collabora Ltd. <http://www.collabora.co.uk/>
-# Copyright (C) 2007 John (J5) Palmieri
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation
-# files (the "Software"), to deal in the Software without
-# restriction, including without limitation the rights to use, copy,
-# modify, merge, publish, distribute, sublicense, and/or sell copies
-# of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-
-from xml.parsers.expat import ExpatError, ParserCreate
-from dbus.exceptions import IntrospectionParserException
-
-class _Parser(object):
- __slots__ = ('map',
- 'in_iface',
- 'in_method',
- 'in_signal',
- 'in_property',
- 'property_access',
- 'in_sig',
- 'out_sig',
- 'node_level',
- 'in_signal')
- def __init__(self):
- self.map = {'child_nodes':[],'interfaces':{}}
- self.in_iface = ''
- self.in_method = ''
- self.in_signal = ''
- self.in_property = ''
- self.property_access = ''
- self.in_sig = []
- self.out_sig = []
- self.node_level = 0
-
- def parse(self, data):
- parser = ParserCreate('UTF-8', ' ')
- parser.buffer_text = True
- parser.StartElementHandler = self.StartElementHandler
- parser.EndElementHandler = self.EndElementHandler
- parser.Parse(data)
- return self.map
-
- def StartElementHandler(self, name, attributes):
- if name == 'node':
- self.node_level += 1
- if self.node_level == 2:
- self.map['child_nodes'].append(attributes['name'])
- elif not self.in_iface:
- if (not self.in_method and name == 'interface'):
- self.in_iface = attributes['name']
- else:
- if (not self.in_method and name == 'method'):
- self.in_method = attributes['name']
- elif (self.in_method and name == 'arg'):
- arg_type = attributes['type']
- arg_name = attributes.get('name', None)
- if attributes.get('direction', 'in') == 'in':
- self.in_sig.append({'name': arg_name, 'type': arg_type})
- if attributes.get('direction', 'out') == 'out':
- self.out_sig.append({'name': arg_name, 'type': arg_type})
- elif (not self.in_signal and name == 'signal'):
- self.in_signal = attributes['name']
- elif (self.in_signal and name == 'arg'):
- arg_type = attributes['type']
- arg_name = attributes.get('name', None)
-
- if attributes.get('direction', 'in') == 'in':
- self.in_sig.append({'name': arg_name, 'type': arg_type})
- elif (not self.in_property and name == 'property'):
- prop_type = attributes['type']
- prop_name = attributes['name']
-
- self.in_property = prop_name
- self.in_sig.append({'name': prop_name, 'type': prop_type})
- self.property_access = attributes['access']
-
-
- def EndElementHandler(self, name):
- if name == 'node':
- self.node_level -= 1
- elif self.in_iface:
- if (not self.in_method and name == 'interface'):
- self.in_iface = ''
- elif (self.in_method and name == 'method'):
- if not self.map['interfaces'].has_key(self.in_iface):
- self.map['interfaces'][self.in_iface]={'methods':{}, 'signals':{}, 'properties':{}}
-
- if self.map['interfaces'][self.in_iface]['methods'].has_key(self.in_method):
- print "ERROR: Some clever service is trying to be cute and has the same method name in the same interface"
- else:
- self.map['interfaces'][self.in_iface]['methods'][self.in_method] = (self.in_sig, self.out_sig)
-
- self.in_method = ''
- self.in_sig = []
- self.out_sig = []
- elif (self.in_signal and name == 'signal'):
- if not self.map['interfaces'].has_key(self.in_iface):
- self.map['interfaces'][self.in_iface]={'methods':{}, 'signals':{}, 'properties':{}}
-
- if self.map['interfaces'][self.in_iface]['signals'].has_key(self.in_signal):
- print "ERROR: Some clever service is trying to be cute and has the same signal name in the same interface"
- else:
- self.map['interfaces'][self.in_iface]['signals'][self.in_signal] = (self.in_sig,)
-
- self.in_signal = ''
- self.in_sig = []
- self.out_sig = []
- elif (self.in_property and name == 'property'):
- if not self.map['interfaces'].has_key(self.in_iface):
- self.map['interfaces'][self.in_iface]={'methods':{}, 'signals':{}, 'properties':{}}
-
- if self.map['interfaces'][self.in_iface]['properties'].has_key(self.in_property):
- print "ERROR: Some clever service is trying to be cute and has the same property name in the same interface"
- else:
- self.map['interfaces'][self.in_iface]['properties'][self.in_property] = (self.in_sig, self.property_access)
-
- self.in_property = ''
- self.in_sig = []
- self.out_sig = []
- self.property_access = ''
-
-
-def process_introspection_data(data):
- """Return a structure mapping all of the elements from the introspect data
- to python types TODO: document this structure
-
- :Parameters:
- `data` : str
- The introspection XML. Must be an 8-bit string of UTF-8.
- """
- try:
- return _Parser().parse(data)
- except Exception, e:
- raise IntrospectionParserException('%s: %s' % (e.__class__, e))
diff --git a/dfeet/_ui/__init__.py b/dfeet/_ui/__init__.py
index 5c8eacb..d7b0c3c 100644
--- a/dfeet/_ui/__init__.py
+++ b/dfeet/_ui/__init__.py
@@ -1,2 +1,2 @@
-from busbox import BusBox
+#from busbox import BusBox
diff --git a/dfeet/_ui/addconnectiondialog.py b/dfeet/_ui/addconnectiondialog.py
index 4cecaf0..643d2d0 100644
--- a/dfeet/_ui/addconnectiondialog.py
+++ b/dfeet/_ui/addconnectiondialog.py
@@ -1,34 +1,56 @@
-from gi.repository import Gtk
+from gi.repository import Gtk, Gio
from uiloader import UILoader
class AddConnectionDialog:
- RESPONSE_CANCEL = -1
- RESPONSE_CONNECT = 1
- def __init__(self, parent):
- ui = UILoader(UILoader.UI_ADDCONNECTIONDIALOG)
+ def __init__(self, parent, address_bus_history=[]):
+ ui = UILoader(UILoader.UI_ADDCONNECTIONDIALOG)
self.dialog = ui.get_root_widget()
- self.combo_entry = ui.get_widget('address_comboentry1')
-
- self.combo_entry.get_child().connect('activate', self.activate_combo)
- self.dialog.add_button('gtk-cancel', self.RESPONSE_CANCEL)
- self.dialog.add_button('gtk-connect', self.RESPONSE_CONNECT)
- def get_address(self):
- return self.combo_entry.get_active_text()
+ #get the hbox and add address combo box with model
+ hbox1 = ui.get_widget('hbox1')
+ self.address_combo_box_store = Gtk.ListStore(str)
+ self.address_combo_box = Gtk.ComboBox.new_with_model_and_entry(self.address_combo_box_store)
+ self.address_combo_box.set_entry_text_column(0)
+ self.label_status = ui.get_widget('label_status')
+
+ hbox1.pack_start(self.address_combo_box, True, True, 0)
+ hbox1.show_all()
+
+ #add history to model
+ for el in address_bus_history:
+ self.address_combo_box_store.append([el])
+
+ self.dialog.add_button('gtk-cancel', Gtk.ResponseType.CANCEL)
+ self.dialog.add_button('gtk-connect', Gtk.ResponseType.OK)
+
+
+ @property
+ def address(self):
+ tree_iter = self.address_combo_box.get_active_iter()
+ if tree_iter != None:
+ model = self.address_combo_box.get_model()
+ return model[tree_iter][0]
+ else:
+ entry = self.address_combo_box.get_child()
+ return entry.get_text()
def run(self):
- return self.dialog.run()
+ response = self.dialog.run()
+ if response == Gtk.ResponseType.CANCEL:
+ return response
+ elif response == Gtk.ResponseType.OK:
+ #check if given address is valid
+ try:
+ is_supported = Gio.dbus_is_supported_address(self.address)
+ except Exception, e:
+ self.label_status.set_text(str(e))
+ self.run()
+ else:
+ return Gtk.ResponseType.OK
+
def destroy(self):
self.dialog.destroy()
- def activate_combo(self, user_data):
- self.dialog.response(self.RESPONSE_CONNECT)
- return True
-
- def set_model(self, model):
- self.combo_entry.set_model(model)
- self.combo_entry.set_text_column(0)
-
diff --git a/dfeet/_ui/busbox.py b/dfeet/_ui/busbox.py
deleted file mode 100644
index 13ba36a..0000000
--- a/dfeet/_ui/busbox.py
+++ /dev/null
@@ -1,95 +0,0 @@
-import gobject
-from gi.repository import Gtk
-
-from dfeet import _util
-
-from busnamebox import BusNameBox
-from busnameinfobox import BusNameInfoBox
-from uiloader import UILoader
-
-class BusBox(Gtk.VBox):
- __gsignals__ = {
- 'introspectnode-selected': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,))
- }
-
- def __init__(self, watch):
- super(BusBox, self).__init__()
-
- # FilterBox
- signal_dict = {
- 'hide_private_toggled' : self.hide_private_toggled_cb,
- 'filter_entry_changed': self.filter_entry_changed_cb
- }
-
-
- self.bus_watch = watch
-
- ui = UILoader(UILoader.UI_FILTERBOX)
- filter_box = ui.get_root_widget()
- filter_entry = ui.get_widget('filter_entry1')
-
- self.pack_start(filter_box, False, False, 0)
-
- self.completion = Gtk.EntryCompletion()
- self.completion.set_model(watch)
- self.completion.set_inline_completion(True)
-
- # older gtk+ does not support this method call
- # but it is not fatal
- try:
- self.completion.set_inline_selection(True)
- except:
- pass
-
- filter_entry.set_completion(self.completion)
-
- # Content
- self.paned = Gtk.HPaned()
- self.busname_box = BusNameBox(watch)
- self.busname_info_box = BusNameInfoBox()
-
- self.busname_box.connect('busname-selected', self.busname_selected_cb)
- self.busname_info_box.connect('selected', self.busname_info_selected_cb)
-
- self.paned.pack1(self.busname_box)
- self.paned.pack2(self.busname_info_box)
- self.paned.set_position(300)
- self.pack_start(self.paned, True, True, 0)
-
- ui.connect_signals(signal_dict)
-
- def busname_selected_cb(self, busname_box, busname):
- self.busname_info_box.set_busname(busname)
-
- def busname_info_selected_cb(self, busname_info_box, node):
- self.emit('introspectnode-selected', node)
-
- def get_selected_introspect_node(self):
- return self.busname_info_box.get_selected_node()
-
- def get_selected_busname(self):
- return self.busname_box.get_selected_busname()
-
- def filter_entry_changed_cb(self, entry, button):
- value = entry.get_text()
- if value == '':
- value = None
-
- self.busname_box.set_filter_string(value)
-
- def hide_private_toggled_cb(self, toggle):
- a = toggle.get_active()
- if a:
- toggle.set_label("Show Private")
- else:
- toggle.set_label("Hide Private")
-
- self.busname_box.set_hide_private(a)
-
- def sort_combo_changed_cb(self, combo):
- value = combo.get_active_text()
- self.busname_box.set_sort_col(value)
-
- def get_bus_watch(self):
- return self.bus_watch
diff --git a/dfeet/_ui/busnamebox.py b/dfeet/_ui/busnamebox.py
deleted file mode 100644
index 393d2a3..0000000
--- a/dfeet/_ui/busnamebox.py
+++ /dev/null
@@ -1,65 +0,0 @@
-import gobject
-from gi.repository import Gtk
-
-from dfeet.dbus_introspector import BusWatch
-
-from busnameview import BusNameView
-
-class BusNameBox(Gtk.VBox):
- __gsignals__ = {
- 'busname-selected' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,))
- }
-
- def __init__(self, watch):
- super(BusNameBox, self).__init__()
-
- self.tree_view = BusNameView(watch)
- self.tree_view.connect('cursor_changed', self.busname_selected_cb)
-
- scroll = Gtk.ScrolledWindow()
- scroll.add(self.tree_view)
- self.pack_start(scroll, True, True, 0)
- scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
-
- self.show_all()
-
- def _completion_match_func(self, completion, key, iter):
- print completion, key, iter
- return self.tree_view._is_iter_equal(completion.get_model(),
- iter, key)
-
- def get_selected_busname(self):
- (model, iter) = self.tree_view.get_selection().get_selected()
- if not iter:
- return None
-
- busname = model.get_value(iter, BusWatch.BUSNAME_OBJ_COL)
-
- return busname
-
- def busname_selected_cb(self, treeview):
- busname = self.get_selected_busname()
- self.emit('busname-selected', busname)
-
- def set_filter_string(self, value):
- self.tree_view.set_filter_string(value)
- self.tree_view.refilter()
-
- def set_hide_private(self, hide_private):
- self.tree_view.set_hide_private(hide_private)
- self.tree_view.refilter()
-
- def set_sort_col(self, value):
- if value == 'Common Name':
- col = BusWatch.COMMON_NAME_COL
- elif value == 'Unique Name':
- col = BusWatch.UNIQUE_NAME_COL
- elif value == 'Process Name':
- col = BusWatch.PROCESS_NAME_COL
- else:
- raise Exception('Value "' + value + '" is not a valid sort value')
-
- self.tree_view.set_sort_column(col)
- #self.tree_view.sort_column_changed()
-
diff --git a/dfeet/_ui/busnameinfobox.py b/dfeet/_ui/busnameinfobox.py
index c84f274..05d1d6f 100644
--- a/dfeet/_ui/busnameinfobox.py
+++ b/dfeet/_ui/busnameinfobox.py
@@ -1,6 +1,6 @@
-import gobject
+from gi.repository import GObject as gobject
from gi.repository import Gtk
-import pango
+from gi.repository import Pango as pango
from dfeet import _util
from dfeet.introspect_data import IntrospectData, Method, Signal
diff --git a/dfeet/_ui/busnameview.py b/dfeet/_ui/busnameview.py
deleted file mode 100644
index eda692a..0000000
--- a/dfeet/_ui/busnameview.py
+++ /dev/null
@@ -1,162 +0,0 @@
-import gobject
-from gi.repository import Gtk
-
-from dfeet.dbus_introspector import BusWatch
-
-class BusNameView(Gtk.TreeView):
- def __init__(self, watch):
- super(BusNameView, self).__init__()
-
- self.hide_private = False
- self.filter_string = None
-
- self.set_property('enable-search', True)
- self.set_property('enable-grid-lines', False)
- self.watch = watch
-
- self.filter_model = self.watch.filter_new(None)
- self.filter_model.set_visible_func(self._filter_cb, None)
-
- self.sort_model = Gtk.TreeModelSort(model=self.filter_model)
- self.sort_model.set_sort_column_id(self.watch.COMMON_NAME_COL, Gtk.SortType.ASCENDING)
- self.sort_model.set_sort_func(self.watch.COMMON_NAME_COL, self._sort_on_name, (self.watch.COMMON_NAME_COL, self.watch.UNIQUE_NAME_COL))
-
- renderer = Gtk.CellRendererPixbuf()
- column = Gtk.TreeViewColumn("",
- renderer,
- pixbuf=watch.ICON_COL
- )
- column.set_resizable(False)
- column.set_sort_column_id(watch.PROCESS_ID_COL)
- self.append_column(column)
-
- renderer = Gtk.CellRendererText()
- column = Gtk.TreeViewColumn("Bus Name",
- renderer,
- markup=watch.DISPLAY_COL
- )
- column.set_resizable(True)
- column.set_sort_column_id(watch.COMMON_NAME_COL)
- self.append_column(column)
-
- """
- column = Gtk.TreeViewColumn("Unique Name",
- renderer,
- text=watch.UNIQUE_NAME_COL
- )
- column.set_resizable(True)
- column.set_sort_column_id(watch.UNIQUE_NAME_COL)
- self.append_column(column)
- """
-
- column = Gtk.TreeViewColumn("Process",
- renderer,
- text=watch.PROCESS_NAME_COL
- )
- column.set_resizable(True)
- column.set_sort_column_id(watch.PROCESS_NAME_COL)
- self.append_column(column)
-
- """
- column = Gtk.TreeViewColumn("PID",
- renderer,
- text=watch.PROCESS_ID_COL
- )
- column.set_resizable(True)
- column.set_sort_column_id(watch.PROCESS_ID_COL)
- self.append_column(column)
- """
-
- self.set_headers_clickable(True)
- self.set_reorderable(False)
- self.set_search_equal_func(self._search_cb, None)
- self.set_model(self.sort_model)
-
- def set_sort_column(self, col):
- self.sort_model.set_sort_column_id(col, Gtk.SortType.ASCENDING)
-
- def set_hide_private(self, value):
- self.hide_private = value
-
- def set_filter_string(self, value):
- self.filter_string = value
-
- def refilter(self):
- self.filter_model.refilter()
-
-
- def _is_iter_equal(self, model, iter, key):
- (unique_name,
- common_name,
- process_id,
- process_path,
- is_public) = model.get(iter,
- BusWatch.UNIQUE_NAME_COL,
- BusWatch.COMMON_NAME_COL,
- BusWatch.PROCESS_ID_COL,
- BusWatch.PROCESS_PATH_COL,
- BusWatch.IS_PUBLIC_COL)
-
- if self.hide_private:
- if not is_public:
- return False
-
- # TODO: support filtering on introspect data
- if key:
- if (unique_name and unique_name.find(key)!=-1) or \
- (common_name and common_name.find(key)!=-1) or \
- str(process_id).startswith(key):
- return True
-
- if process_path:
- for item in process_path:
- if (item.find(key)!=-1):
- return True
-
- return False
-
- return True
-
-
- def _search_cb(self, model, column, key, iter_):
- return not self._is_iter_equal(model, iter_, key)
-
- def _filter_cb(self, model, iter_, data):
- return self._is_iter_equal(model, iter_, self.filter_string)
-
- def _sort_on_name(self, model, iter1, iter2, cols):
- (col, alt_col) = cols
-
- un1 = model.get_value(iter1, col)
- un2 = model.get_value(iter2, col)
-
- if un1 is None:
- un1 = model.get_value(iter1, alt_col)
-
- if un2 is None:
- un2 = model.get_value(iter2, alt_col)
-
- # covert to integers if comparing two unique names
- if un1[0] == ':' and un2[0] == ':':
- un1 = un1[1:].split('.')
- un1 = tuple(map(int, un1))
-
- un2 = un2[1:].split('.')
- un2 = tuple(map(int, un2))
-
- elif un1[0] == ':' and un2[0] != ':':
- return 1
- elif un1[0] != ':' and un2[0] == ':':
- return -1
- else:
- un1 = un1.split('.')
- un2 = un2.split('.')
-
- if un1 == un2:
- return 0
- elif un1 > un2:
- return 1
- else:
- return -1
-
-
diff --git a/dfeet/_ui/executemethoddialog.py b/dfeet/_ui/executemethoddialog.py
index 7a542ae..564303f 100644
--- a/dfeet/_ui/executemethoddialog.py
+++ b/dfeet/_ui/executemethoddialog.py
@@ -1,33 +1,13 @@
-from gi.repository import Gtk
-import dbus
-
-from dfeet import _util
-
-from uiloader import UILoader
-
+# -*- coding: utf-8 -*-
+import time
from pprint import pformat
+from gi.repository import Gtk, GLib, Gio
-def unwrap(x):
- """Hack to unwrap D-Bus values, so that they're easier to read when
- printed."""
-
- if isinstance(x, list):
- return map(unwrap, x)
-
- if isinstance(x, tuple):
- return tuple(map(unwrap, x))
-
- if isinstance(x, dict):
- return dict([(unwrap(k), unwrap(v)) for k, v in x.iteritems()])
-
- for t in [unicode, str, long, int, float, bool]:
- if isinstance(x, t):
- return t(x)
+from uiloader import UILoader
- return x
class ExecuteMethodDialog:
- def __init__(self, busname, method):
+ def __init__(self, connection, connection_is_bus, bus_name, method_obj):
signal_dict = {
'execute_dbus_method_cb' : self.execute_cb,
'execute_dialog_close_cb': self.close_cb
@@ -35,62 +15,102 @@ class ExecuteMethodDialog:
ui = UILoader(UILoader.UI_EXECUTEDIALOG)
self.dialog = ui.get_root_widget()
- self.command_label = ui.get_widget('commandlabel1')
+ self.label_method_name = ui.get_widget('label_method_name')
+ self.label_object_path = ui.get_widget('label_object_path')
+ self.label_interface = ui.get_widget('label_interface')
self.notebook = ui.get_widget('notebook1')
self.parameter_textview = ui.get_widget('parametertextview1')
self.source_textview = ui.get_widget('sourcetextview1')
- self.notebook.set_tab_label_text(self.source_textview.get_parent(),
- 'Source')
self.prettyprint_textview = ui.get_widget('prettyprinttextview1')
- self.notebook.set_tab_label_text(self.prettyprint_textview.get_parent(),
- 'Pretty Print')
+ self.method_execution_count_spinbutton = ui.get_widget('method_exec_count_spinbutton')
+ self.label_avg = ui.get_widget('label_avg')
+ self.label_min = ui.get_widget('label_min')
+ self.label_max = ui.get_widget('label_max')
ui.connect_signals(signal_dict)
- self.busname = busname
- self.method = method
+ self.connection = connection
+ self.connection_is_bus = connection_is_bus
+ self.bus_name = bus_name
+ self.method_obj = method_obj
- # FIXME: get the interface and object path
- text = 'Execute ' + str(self.method)
- self.command_label.set_text(text)
+ self.label_method_name.set_markup("%s" % (self.method_obj.markup_str))
+ self.label_object_path.set_markup("%s" % (self.method_obj.object_path))
+ self.label_interface.set_markup("%s" % (self.method_obj.iface_info.name))
def execute_cb(self, widget):
- # TODO: make call async, time it and add spinner to dialog
+ #get given parameters
+ buf = self.parameter_textview.get_buffer()
+ params = buf.get_text(buf.get_start_iter(),
+ buf.get_end_iter(), False)
+
+ #reset the statistics stuff
+ self.label_avg.set_text("")
+ self.label_min.set_text("")
+ self.label_max.set_text("")
+ user_data = {
+ 'avg': 0,
+ 'count': 0,
+ }
+
try:
- args = ()
- buf = self.parameter_textview.get_buffer()
- params = buf.get_text(buf.get_start_iter(),
- buf.get_end_iter())
+ #build a GVariant
if params:
params = '(' + params + ',)'
- args = eval(params, {'Boolean':dbus.Boolean,
- 'Byte':dbus.Byte,
- 'Int16':dbus.Int16,
- 'Int32':dbus.Int32,
- 'Int64':dbus.Int64,
- 'UInt16':dbus.UInt16,
- 'UInt32':dbus.UInt32,
- 'UInt64':dbus.UInt64,
- 'Double':dbus.Double,
- 'ObjectPath':dbus.ObjectPath,
- 'Signature':dbus.Signature,
- 'String':dbus.String,
- 'UTF8String':dbus.UTF8String})
-
- result = self.method.dbus_call(self.busname.get_bus(),
- self.busname.get_display_name(),
- *args)
- except Exception, e: # FIXME: treat D-Bus errors differently
- # from parameter errors?
- result = str(e)
-
- if result is None:
- result = 'This method did not return anything'
-
- prettified = pformat(unwrap(result))
- self.prettyprint_textview.get_buffer().set_text(prettified)
-
- self.source_textview.get_buffer().set_text(str(result))
-
+ params_gvariant = GLib.Variant.parse(None, params, None, None)
+ else:
+ params_gvariant = None
+
+ if self.connection_is_bus:
+ proxy = Gio.DBusProxy.new_sync(self.connection,
+ Gio.DBusProxyFlags.NONE,
+ None,
+ self.bus_name,
+ self.method_obj.object_path,
+ self.method_obj.iface_info.name,
+ None)
+ #call the function
+ for i in range(0, self.method_execution_count_spinbutton.get_value_as_int()):
+ user_data['method_call_time_start'] = time.time()
+ proxy.call(self.method_obj.method_info.name, params_gvariant, Gio.DBusCallFlags.NONE, -1, None, self.method_connection_bus_cb, user_data)
+ else:
+ #FIXME: implement p2p connection execution
+ raise Exception("Function execution on p2p connections not yet implemented")
+ #self.connection.call(None, object_path, self.method_obj.iface_obj.iface_info.name, self.method_obj.method_info.name, params_gvariant, GLib.VariantType.new("(s)"), Gio.DBusCallFlags.NONE, -1, None)
+
+
+ except Exception, e:
+ #output the exception
+ self.source_textview.get_buffer().set_text(str(e))
+ self.prettyprint_textview.get_buffer().set_text(pformat(str(e)))
+
+
+ def method_connection_bus_cb(self, proxy, res_async, user_data):
+ """ async callback for executed method """
+ try:
+ #get the result from the dbus method call
+ result = proxy.call_finish(res_async)
+ #remember the needed time for the method call
+ method_call_time_end = time.time()
+ method_call_time_needed = method_call_time_end - user_data['method_call_time_start']
+
+ #update avg, min, max
+ user_data['avg'] += method_call_time_needed
+ user_data['count'] += 1
+ self.label_avg.set_text("%.4f" % (float(user_data['avg'] / user_data['count'])))
+ self.label_min.set_text("%.4f" % min(float(self.label_min.get_text() or "999"), method_call_time_needed))
+ self.label_max.set_text("%.4f" % max(float(self.label_max.get_text() or "0"), method_call_time_needed))
+
+ #output result
+ if result:
+ self.source_textview.get_buffer().set_text(str(result))
+ self.prettyprint_textview.get_buffer().set_text(str(result.unpack()[0]))
+ else:
+ self.prettyprint_textview.get_buffer().set_text('This method did not return anything')
+ except Exception, e:
+ #output the exception
+ self.source_textview.get_buffer().set_text(str(e))
+ self.prettyprint_textview.get_buffer().set_text(pformat(str(e)))
+
def run(self):
self.dialog.run()
diff --git a/dfeet/_ui/uiloader.py b/dfeet/_ui/uiloader.py
index a25ead1..2a38875 100644
--- a/dfeet/_ui/uiloader.py
+++ b/dfeet/_ui/uiloader.py
@@ -1,41 +1,40 @@
+# -*- coding: utf-8 -*-
+import os
from gi.repository import Gtk
-from dfeet import _util
class UILoader:
instance = None
- UI_COUNT = 5
+ UI_COUNT = 5
(UI_MAINWINDOW,
- UI_FILTERBOX,
- UI_INTROSPECTVIEW,
+ UI_INTROSPECTION,
+ UI_BUSWATCH,
UI_EXECUTEDIALOG,
UI_ADDCONNECTIONDIALOG
) = range(UI_COUNT)
# {ui_id: ((files,...), root widget)}
- _ui_map = {UI_MAINWINDOW : (('default-actiongroup.ui','mainwindow.ui'),
- 'appwindow1'),
- UI_FILTERBOX : (('filterbox.ui',),
- 'filterbox_table1'),
- UI_INTROSPECTVIEW : (('introspectview.ui',),
- 'introspectview_table1'),
- UI_EXECUTEDIALOG : (('executedialog.ui',),
- 'executedialog1'),
+ _ui_map = {UI_MAINWINDOW : (('mainwindow.ui',),
+ 'appwindow1'),
+ UI_INTROSPECTION : (('introspection.ui',),
+ 'box_introspectview'),
+ UI_BUSWATCH : (('buswatch.ui',),
+ 'paned_buswatch'),
+ UI_EXECUTEDIALOG : (('executedialog.ui',),
+ 'executedialog1'),
UI_ADDCONNECTIONDIALOG : (('addconnectiondialog.ui',),
'add_connection_dialog1')
}
def __init__(self, ui):
- ui_dir = _util.get_ui_dir()
-
ui_info = self._ui_map[ui]
self.ui = Gtk.Builder()
#load ui files
for file in ui_info[0]:
- self.ui.add_from_file(ui_dir + '/' + file)
+ self.ui.add_from_file(self.ui_dir + '/' + file)
self.root_widget_name = ui_info[1]
@@ -48,3 +47,12 @@ class UILoader:
def connect_signals(self, obj_or_map):
self.ui.connect_signals(obj_or_map)
+ @property
+ def ui_dir(self):
+ try:
+ ui_dir = os.environ['DFEET_DATA_PATH']
+ except:
+ ui_dir = "../ui"
+
+ return ui_dir
+
diff --git a/dfeet/_ui/wnck_utils.py b/dfeet/_ui/wnck_utils.py
index a5f1e21..3b77e9a 100644
--- a/dfeet/_ui/wnck_utils.py
+++ b/dfeet/_ui/wnck_utils.py
@@ -2,7 +2,7 @@
# icon information. If the wnck module is not installed we fallback to default
# behvior
-import gobject
+from gi.repository import GObject as gobject
from gi.repository import Gtk
try:
diff --git a/dfeet/_util.py b/dfeet/_util.py
deleted file mode 100644
index e0ebc94..0000000
--- a/dfeet/_util.py
+++ /dev/null
@@ -1,32 +0,0 @@
-import os
-
-# TODO: Check against other Unix's
-def get_proc_from_pid(pid):
- procpath = '/proc/' + str(pid) + '/cmdline'
- fullpath = ''
-
- try:
- f = open(procpath, 'r')
- fullpath = f.readline().split('\0')
- f.close()
- except:
- pass
-
- return fullpath
-
-# TODO: figure out more robust way to do this
-def get_ui_dir():
- try:
- ui_dir = os.environ['DFEET_DATA_PATH']
- except:
- ui_dir = "../ui"
-
- return ui_dir
-
-def print_method(m):
- def decorator(*args):
- print "call:", m,args
- r = m(*args)
- print "return:", r
- return r
- return decorator
diff --git a/dfeet/bus_watch.py b/dfeet/bus_watch.py
new file mode 100644
index 0000000..f3db940
--- /dev/null
+++ b/dfeet/bus_watch.py
@@ -0,0 +1,215 @@
+# -*- coding: utf-8 -*-
+
+import os
+from gi.repository import GObject, GdkPixbuf, Gtk, Gio, GLib
+from _ui.uiloader import UILoader
+from introspection import AddressInfo
+
+
+class DBusBusName(GObject.GObject):
+ """ class to represent a name on the bus """
+ def __init__(self, bus_name_unique):
+ super(DBusBusName, self).__init__()
+ self.__bus_name_unique = bus_name_unique
+ self.__pid = 0
+ self.__cmdline = ''
+
+ def __repr__(self):
+ return u"%s (pid: %s)" % (self.bus_name_unique, self.pid)
+
+ def __update_cmdline(self):
+ if self.pid > 0:
+ procpath = '/proc/' + str(self.pid) + '/cmdline'
+ with open(procpath, 'r') as f:
+ self.__cmdline = " ".join(f.readline().split('\0'))
+ else:
+ self.__cmdline = ''
+
+ @property
+ def bus_name_unique(self):
+ return self.__bus_name_unique
+
+ @property
+ def pid(self):
+ return self.__pid
+
+ @pid.setter
+ def pid(self, pid_new):
+ self.__pid = pid_new
+ try:
+ self.__update_cmdline()
+ except Exception, e:
+ self.__cmdline = ''
+
+ @property
+ def cmdline(self):
+ return self.__cmdline
+
+
+class BusWatch:
+ """ watch for a given bus """
+ def __init__(self, address):
+ self.address = address
+ #setup UI
+ ui = UILoader(UILoader.UI_BUSWATCH)
+ self.paned_buswatch = ui.get_root_widget()
+ self.liststore_model = ui.get_widget('liststore_buswatch')
+ self.treeview = ui.get_widget('treeview_buswatch')
+ self.entry_filter = ui.get_widget('entry_filter')
+ self.grid_bus_name_selected_info = ui.get_widget('grid_bus_name_info')
+ self.label_bus_name_selected_name = ui.get_widget('label_bus_name_selected_name')
+ self.label_bus_name_selected_pid = ui.get_widget('label_bus_name_selected_pid')
+ self.label_bus_name_selected_cmdline = ui.get_widget('label_bus_name_selected_cmdline')
+ self.addr_info = None # hold the currently selected AddressInfo object
+
+ self.treeview.connect('cursor-changed',
+ self.__tree_view_cursor_changed_cb)
+
+
+ #setup the conection
+ if self.address == Gio.BusType.SYSTEM or self.address == Gio.BusType.SESSION:
+ self.connection = Gio.bus_get_sync(self.address, None)
+ elif Gio.dbus_is_supported_address(self.address) == True:
+ self.connection = Gio.DBusConnection.new_for_address_sync(self.address,
+ Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT | Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION,
+ None, None)
+
+ #setup signals
+ self.connection.signal_subscribe(None, "org.freedesktop.DBus", "NameOwnerChanged",
+ None, None, 0, self.__name_owner_changed_cb, None)
+
+ self.bus_proxy = Gio.DBusProxy.new_sync(self.connection,
+ Gio.DBusProxyFlags.NONE,
+ None,
+ 'org.freedesktop.DBus',
+ '/org/freedesktop/DBus',
+ 'org.freedesktop.DBus', None)
+
+ #list all names
+ self.bus_proxy.ListNames('()',
+ result_handler=self.__list_names_handler,
+ error_handler=self.__list_names_error_handler)
+
+ def __tree_view_cursor_changed_cb(self, treeview):
+ """ do something when a row is selected """
+ selection = self.treeview.get_selection()
+ if selection:
+ model, iter = selection.get_selected()
+ if not iter:
+ return
+
+ bus_name_obj = model.get(iter, 0)[0]
+ #remove current child
+ c2 = self.paned_buswatch.get_child2()
+ if c2:
+ c2.destroy()
+ try:
+ del(self.addr_info)
+ except:
+ pass
+
+ #add Introspection to paned
+ self.addr_info = AddressInfo(self.address, bus_name_obj.bus_name_unique, connection_is_bus=True)
+ self.paned_buswatch.add2(self.addr_info.introspect_box)
+
+ #update info about selected bus name
+ self.label_bus_name_selected_name.set_text(bus_name_obj.bus_name_unique)
+ self.label_bus_name_selected_pid.set_text("%s" % bus_name_obj.pid)
+ self.label_bus_name_selected_cmdline.set_text(bus_name_obj.cmdline)
+ self.grid_bus_name_selected_info.set_visible(True)
+
+
+ def __liststore_model_add(self, bus_name_obj):
+ """ add a DBusBusName object to the liststore model """
+ #update bus info stuff
+ self.bus_proxy.GetConnectionUnixProcessID('(s)', bus_name_obj.bus_name_unique,
+ result_handler = self.__get_unix_process_id_cb,
+ error_handler = self.__get_unix_process_id_error_cb,
+ user_data=bus_name_obj)
+ #add bus to liststore
+ return self.liststore_model.append([bus_name_obj, 0, u"%s" % (bus_name_obj.bus_name_unique), bus_name_obj.cmdline])
+
+
+ def __liststore_model_remove(self, bus_name_obj):
+ """ remove a DBusBusName object to the liststore model """
+ for n, obj in enumerate(self.liststore_model):
+ if obj[2] == bus_name_obj.bus_name_unique:
+ del(self.liststore_model[n])
+ break
+
+ def __liststore_model_get(self, bus_name_obj):
+ """ get a object from the liststore """
+ for n, obj in enumerate(self.liststore_model):
+ if obj[2] == bus_name_obj.bus_name_unique:
+ return obj
+ raise Exception("bus name object '%s' not found in liststore" % (bus_name_obj))
+
+
+ def __name_owner_changed_cb(self, connection, sender_name, object_path, interface_name, signal_name, parameters, user_data):
+ """ bus name added or removed """
+ bus_name = parameters[0]
+ old_owner = parameters[1]
+ new_owner = parameters[2]
+
+ bus_name_obj = DBusBusName(bus_name)
+
+ if bus_name[0] == ':':
+ if not old_owner:
+ self.__liststore_model_add(bus_name_obj)
+ else:
+ self.__liststore_model_remove(bus_name_obj)
+ else :
+ if new_owner:
+ self.__liststore_model_add(bus_name_obj)
+ if old_owner:
+ self.__liststore_model_remove(bus_name_obj)
+
+
+ def __list_names_handler(self, obj, names, userdata):
+ for n in names:
+ bus_name_obj = DBusBusName(n)
+ self.__liststore_model_add(bus_name_obj)
+
+
+ def __list_names_error_handler(self, obj, error, userdata):
+ print "error getting bus names: %s" % str(error)
+
+
+ def __get_unix_process_id_cb(self, obj, pid, bus_name_obj):
+ bus_name_obj.pid = pid
+
+
+ def __get_unix_process_id_error_cb(self, obj, error, bus_name_obj):
+ print "error getting unix process id for %s: %s" % (bus_name_obj.bus_name_unique, str(error))
+ bus_name_obj.pid = 0
+
+
+if __name__ == "__main__":
+ """ for debugging """
+ import sys
+ import argparse
+
+ parser = argparse.ArgumentParser(description='show a given bus address')
+ parser.add_argument('addr')
+ p = parser.parse_args()
+
+ if p.addr.lower() == 'system':
+ addr = Gio.BusType.SYSTEM
+ elif p.addr.lower() == 'session':
+ addr = Gio.BusType.SESSION
+ else:
+ addr = p.addr
+
+ bw = BusWatch(addr)
+
+ win = Gtk.Window()
+ win.connect("delete-event", Gtk.main_quit)
+ win.set_default_size(1024, 768)
+ win.add(bw.paned_buswatch)
+ win.show_all()
+ try:
+ Gtk.main()
+ except (KeyboardInterrupt, SystemExit):
+ Gtk.main_quit()
+
+
diff --git a/dfeet/dbus_introspector.py b/dfeet/dbus_introspector.py
deleted file mode 100644
index 5bda27d..0000000
--- a/dfeet/dbus_introspector.py
+++ /dev/null
@@ -1,477 +0,0 @@
-
-from gi.repository import GObject, Gdk, GdkPixbuf, Gtk, Gio
-import _util
-import _introspect_parser
-import os
-import _ui.wnck_utils
-
-from introspect_data import IntrospectData
-
-SESSION_BUS = 1
-SYSTEM_BUS = 2
-ADDRESS_BUS = 3
-
-class Error(Exception):
- pass
-
-class BusAddressError(Error):
- def __init__(self, address):
- self.address = address
-
- def __str__(self):
- return repr('Bus address \'%s\' is not a valid bus address' % self.address)
-
-class InvalidColumnError(Error):
- def __init__(self, col):
- self.column = col
-
- def __str__(self):
- return repr('Column number \'%i\' requested but is not valid' % self.column)
-
-class CommonNameData(GObject.GObject):
- __gsignals__ = {
- 'introspect_data_changed' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE,())
- }
-
- def __init__(self):
- super(CommonNameData, self).__init__()
-
- self.unique_name = None
- self.bus = None
- self.process_id = None
- self.process_path = None
- self.process_name = 'Unknown or Remote'
- self._introspecting = False
- self._introspection_data = IntrospectData()
- self._introspect_object_queue = []
-
- # there is a race condition here but D-Bus
- # doesn't have a signal for introspection data change
- # which would be impractical for some highly dynamic objects
- def _introspect(self, name, node):
- self._introspecting = True
- obj = self.bus.get_object(name, node, follow_name_owner_changes=True)
- obj.Introspect(dbus_interface='org.freedesktop.DBus.Introspectable',
- reply_handler=lambda xml: self._query_introspect_data_cb(name, node, xml),
- error_handler=self._query_introspect_data_error_cb)
-
- def _query_introspect_data_error_cb(self, error):
- print error
- self._introspecting = False
- # errors are expected
-
- def _query_introspect_data_cb(self, name, parent_node, xml):
- self._introspecting = False
- data = _introspect_parser.process_introspection_data(xml)
- for node in data['child_nodes']:
- cnode = ''
- if parent_node != '/':
- cnode = parent_node
-
- cnode += '/' + node
- self._introspect_object_queue.append(cnode)
-
- if self._introspect_object_queue:
- obj = self._introspect_object_queue.pop(0)
- self._introspect(name, obj)
-
- if data['interfaces']:
- self._introspection_data.append(parent_node, data)
-
-
- self.emit('introspect_data_changed')
-
-class BusName(GObject.GObject):
- __gsignals__ = {
- 'changed' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE,())
- }
-
-
- def __init__(self, unique_name, bus, common_name = None, clone_from_busname = None):
-
- super(BusName, self).__init__()
-
- if not clone_from_busname:
- self.common_data = CommonNameData()
- else:
- self.common_data = clone_from_busname.common_data
-
- if common_name:
- self.set_common_name(str(common_name))
- else:
- self.clear_common_name()
-
- self.common_data.bus = bus
- self.common_data.unique_name = str(unique_name)
- self.common_data.connect('introspect_data_changed',
- self._introspect_data_changed_cb)
-
- self.busname_is_public = not (not common_name)
-
- def query_introspect(self, node = '/'):
- self.common_data._introspect(self.get_display_name(), node)
-
- def _introspect_data_changed_cb(self, data):
- '''
- print "*********************************************"
- print len(data._introspection_data.object_paths.object_path_list)
- i = 0
- for o in data._introspection_data.object_paths.object_path_list:
- print i, o
- i+=1
- print "*********************************************"'''
- self.emit('changed')
-
- def set_common_name(self, common_name):
- self.busname_is_public = True
- self.common_name = common_name
- self.emit('changed')
-
- def get_display_name(self):
- if self.is_public():
- result = self.get_common_name()
- else:
- result = self.get_unique_name()
-
- return result
-
- def get_icon(self):
- icon_table = _ui.wnck_utils.IconTable.get_instance()
- return icon_table.get_icon(self.get_process_id())
-
- def get_bus(self):
- return self.common_data.bus
-
- def clear_common_name(self):
- self.busname_is_public = False
- self.common_name = None
-
- def is_public(self):
- return self.busname_is_public
-
- def set_process_info(self, id, path):
- self.common_data.process_id = id
- self.common_data.process_path = path
- if path:
- self.common_data.process_name = os.path.basename(path[0])
-
- self.emit('changed')
-
- def get_unique_name(self):
- return self.common_data.unique_name
-
- def get_common_name(self):
- return self.common_name
-
- def get_process_id(self):
- return self.common_data.process_id
-
- def get_process_path(self):
- return self.common_data.process_path
-
- def get_process_name(self):
- return self.common_data.process_name
-
- def __str__(self):
- result = self.common_data.unique_name
- result += '\n Process ID: '
- if self.common_data.process_id:
- result += str(self.common_data.process_id)
- else:
- result += 'Unknown'
-
- result += '\n Process Name: '
- if self.common_data.process_path:
- result += self.common_data.process_name
- else:
- result += 'Unknown'
-
- result += '\n Well Known Name'
- if not self.common_name:
- result += ': None'
- else:
- result += ': '
- result += self.common_name
-
- return result
-
-class BusWatch(Gtk.ListStore):
- NUM_COL = 9
-
- (BUSNAME_OBJ_COL,
- UNIQUE_NAME_COL,
- COMMON_NAME_COL,
- IS_PUBLIC_COL, # has a common name
- PROCESS_ID_COL,
- PROCESS_PATH_COL,
- PROCESS_NAME_COL,
- DISPLAY_COL,
- ICON_COL) = range(NUM_COL)
-
- COL_TYPES = (GObject.TYPE_PYOBJECT,
- GObject.TYPE_STRING,
- GObject.TYPE_STRING,
- GObject.TYPE_BOOLEAN,
- GObject.TYPE_STRING,
- GObject.TYPE_PYOBJECT,
- GObject.TYPE_STRING,
- GObject.TYPE_STRING,
- GdkPixbuf.Pixbuf)
-
- def __init__(self, bus, address=None):
- self.bus = None
- self.unique_names = {}
- self.name_list = []
- self.bus_type = bus
- self.address = address
- #self.completion_model = Gtk.ListStore()
-
- super(BusWatch, self).__init__(*self.COL_TYPES)
-
- if bus == SESSION_BUS:
- self.bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
- elif bus == SYSTEM_BUS:
- self.bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
- else:
- if not address:
- raise BusAddressError(address)
- self.bus = Gio.DBusConnection.new_for_address_sync(
- address,
- Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION,
- None, None)
-
- if not self.bus:
- raise BusAddressError(address)
-
- self.bus.signal_subscribe('',
- 'org.freedesktop.DBus',
- 'NameOwnerChanged',
- '',
- '',
- 0,
- self.name_owner_changed_cb,
- None)
- self.bus_proxy = Gio.DBusProxy.new_sync(self.bus,
- Gio.DBusProxyFlags.NONE,
- None,
- 'org.freedesktop.DBus',
- '/org/freedesktop/DBus',
- 'org.freedesktop.DBus', None)
-
- self.bus_proxy.ListNames('()',
- result_handler=self.list_names_handler,
- error_handler=self.list_names_error_handler)
-
- def get_bus_name(self):
- if self.bus_type == SESSION_BUS:
- return "Session Bus"
- elif self.bus_type == SYSTEM_BUS:
- return "System Bus"
- else:
- return self.address
-
- def get_bus_type(self):
- return self.bus_type
-
- def get_bus_address(self):
- return self.address
-
- def close_bus(self):
- self.bus.close()
-
- def close_bus(self):
- self.bus.close()
-
- def get_completion_model(self):
- return self.completion_model()
-
- def get_unix_process_id_cb(self, obj, id_, name):
- names = self.unique_names[name]
- if not names:
- return
-
- name = names[0]
- if not name:
- return
-
- process_path = _util.get_proc_from_pid(id_)
- name.set_process_info(id_, process_path)
-
- def get_unix_process_id_error_cb(self, obj, error, name):
- print error
-
- # get the Unix process ID so we can associate the name
- # with a process (this will only work under Unix like OS's)
- def get_unix_process_id_async_helper(self, name):
- self.bus_proxy.GetConnectionUnixProcessID('(s)', name,
- result_handler = self.get_unix_process_id_cb,
- error_handler = self.get_unix_process_id_error_cb,
- user_data=name)
-
-
- def name_changed_cb(self, name):
- pass
- path = (self.name_list.index(name,))
- iter = self.get_iter(path)
- self.row_changed(path, iter)
-
- # if name is not unique and owner is set add the name to the BusName object
- # else create a new BusName object
- def add_name(self, name, owner=None):
- if name[0] == ':':
- if self.unique_names.has_key(name):
- return
-
- busnameobj = BusName(name, self.bus)
- busnameobj.connect('changed', self.name_changed_cb)
- self.unique_names[name] = [busnameobj]
- self.get_unix_process_id_async_helper(name)
- self.name_list.append(busnameobj)
-
- self.append((busnameobj,
- busnameobj.get_unique_name(),
- busnameobj.get_common_name(),
- busnameobj.is_public(),
- busnameobj.get_process_id(),
- busnameobj.get_process_path(),
- busnameobj.get_process_name(),
- busnameobj.get_unique_name(),
- busnameobj.get_icon()))
- else:
- if not owner:
- owner = self.bus_proxy.GetNameOwner('(s)', name)
- if owner == 'org.freedesktop.DBus':
- return
-
- # if owner still does not exist then we move on
- if not owner:
- return
-
- if self.unique_names.has_key(owner):
- busnameobj = self.unique_names[owner][0]
- if busnameobj.is_public():
- busnameobj = BusName(owner, self.bus, name, busnameobj)
- self.unique_names[owner].append(busnameobj)
- self.name_list.append(busnameobj)
-
- self.append((busnameobj,
- busnameobj.get_unique_name(),
- busnameobj.get_common_name(),
- busnameobj.is_public(),
- busnameobj.get_process_id(),
- busnameobj.get_process_path(),
- busnameobj.get_process_name(),
- busnameobj.get_common_name(),
- busnameobj.get_icon()))
- else:
- busnameobj.set_common_name(name)
-
- else:
- busnameobj = BusName(owner, self.bus, name)
- self.unique_names[owner] = [busnameobj]
- self.name_list.append(busnameobj)
- self.get_unix_process_id_async_helper(owner)
- self.append((busnameobj,
- busnameobj.get_unique_name(),
- busnameobj.get_common_name(),
- busnameobj.is_public(),
- busnameobj.get_process_id(),
- busnameobj.get_process_path(),
- busnameobj.get_process_name(),
- busnameobj.get_common_name(),
- busnameobj.get_icon()))
-
- def remove_name(self, name, owner=None):
- if not name:
- return
-
- if self.unique_names.has_key(name):
- busnames = self.unique_names[name]
- for n in busnames:
- self.remove_name(n.common_name, name)
-
- index = self.name_list.index(self.unique_names[name][0])
- self.name_list.pop(index)
-
- del(self.unique_names[name])
- self.row_deleted((index,))
- else:
- if not owner:
- return
-
- # names may have been deleted already
- if self.unique_names.has_key(owner):
- busnames = self.unique_names[owner]
- if len(busnames) == 1:
- if busnames[0].common_name == name:
- busnames[0].clear_common_name()
- path = (self.name_list.index(busnames[0]),)
- iter = self.get_iter(path)
- self.row_changed(path, iter)
- else:
- for n in busnames:
- if n.common_name == name:
- self.unique_names[owner].remove(n)
- index = self.name_list.index(n)
- self.name_list.pop(index)
- self.row_deleted((index,))
-
- def name_owner_changed_cb(self, name, old_owner, new_owner):
- if name[0] == ':':
- if not old_owner:
- self.add_name(name)
- else:
- self.remove_name(name)
-
- else :
- if new_owner:
- self.add_name(name, new_owner)
-
- if old_owner:
- self.remove_name(name, old_owner)
-
- def list_names_handler(self, obj, results, userdata):
- names = results
- for n in names:
- self.add_name(n)
-
- def list_names_error_handler(self, obj, error, userdata):
- print "error getting bus names - %s" % str(error)
-
- def get_name_list(self):
- return self.name_list
-
- def on_get_value(self, rowref, column):
- name = rowref[0]
- child = -1
- if len(rowref) > 1:
- child = rowref[1]
-
- if column == self.BUSNAME_OBJ_COL:
- return name
- elif column == self.UNIQUE_NAME_COL:
- return name.get_unique_name()
- elif column == self.COMMON_NAME_COL:
- return name.get_common_name()
- elif column == self.IS_PUBLIC_COL:
- return name.is_public()
- elif column == self.PROCESS_ID_COL:
- return name.get_process_id()
- elif column == self.PROCESS_PATH_COL:
- return name.get_process_path()
- elif column == self.PROCESS_NAME_COL:
- return name.get_process_name()
- elif column == self.ICON_COL:
- return name.get_icon()
- elif column == self.DISPLAY_COL:
- if child == -1:
- return '<b>' + GObject.markup_escape_text(name.get_display_name()) + '</b>'
- elif child == 1:
- return '<b>Command Line: </b>' + GObject.markup_escape_text(name.get_process_name()) + ' (' + GObject.markup_escape_text(str(name.get_process_id())) + ')'
- elif child == 0:
- return '<b>Unique Name: </b>'+ GObject.markup_escape_text(name.get_unique_name())
- else:
- raise InvalidColumnError(column)
-
- return None
-
diff --git a/dfeet/dbus_utils.py b/dfeet/dbus_utils.py
index 10554bf..fa38ba5 100644
--- a/dfeet/dbus_utils.py
+++ b/dfeet/dbus_utils.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
def convert_complex_type(subsig):
result = None
len_consumed = 0
diff --git a/dfeet/introspect_data.py b/dfeet/introspect_data.py
deleted file mode 100644
index 8a71746..0000000
--- a/dfeet/introspect_data.py
+++ /dev/null
@@ -1,678 +0,0 @@
-from gi.repository import Gtk
-import gobject
-import dbus_utils
-import dbus
-import _util
-
-class Node:
- def __init__(self, model, parent = None):
- self.child_list = []
- self.parent = parent
- self.model = model
- self.expanded = False
- self.valid = True
-
- # default markup for signatures
- self.sig_props = 'foreground="#2E8B57" size="smaller"'
- self.name_props = 'foreground="#000000" size="smaller"'
-
- def on_selected(self, busname):
- # do nothing here but this is called whenever
- # a node is selected in the model so can be
- # overridden (see Property class for example)
- pass
-
- def mark_tree_invalid(self):
- self.valid = False
- for child in self.child_list:
- child.mark_tree_invalid()
-
- def mark_valid(self):
- self.valid = True
-
- def reap_ivalid(self):
- for child in self.child_list:
- if child.reap_invalid():
- pass
- # FIXME - we need to reap items that are no longer valid
- return not self.valid
-
- def set_expanded(self, expanded):
- self.expanded = expanded
-
- def is_expanded(self):
- expanded = False
- if self.child_list:
- expanded = self.expanded
-
- return expanded
-
- def index(self, child):
- return self.child_list.index(child)
-
- def on_get_iter(self, path):
- op = self.child_list[path[0]]
- if len(path) == 1:
- return op
- else:
- return op.on_get_iter(path[1:])
-
- def get_path_pos(self):
- pos = 0
- if self.parent:
- pos = self.parent.index(self)
-
- return pos
-
- def get_next(self):
- next = None
- if self.parent:
- next = self.parent.get_next_child(self)
-
- return next
-
- def get_next_child(self, child):
- i = self.index(child)
- try:
- return self.child_list[i+1]
- except IndexError:
- return None
-
- def get_first_child(self):
- if self.child_list:
- return self.child_list[0]
- else:
- return None
-
- def get_nth_child(self, n):
- try:
- return self.child_list[n]
- except IndexError:
- return None
-
- def count_children(self):
- c = len(self.child_list)
- return c
-
- def _row_changed(self, path):
- iter = self.model.get_iter(path)
- self.model.row_changed(path, iter)
-
- def _row_inserted(self, path):
- iter = self.model.get_iter(path)
- self.model.row_inserted(path, iter)
-
- def _calculate_path(self, *append_args):
- p = [self.get_path_pos()]
- parent = self.parent
- while parent:
- p.insert(0, parent.get_path_pos())
- parent = parent.parent
-
- for pos in append_args:
- p.append(pos)
-
- return p
-
- def append(self, child):
- self.insert(-1, child)
-
- def insert(self, i, child):
- if i == -1:
- self.child_list.append(child)
- i = len(self.child_list) - 1
- else:
- self.child_list.insert(i, child)
-
- child_path = self._calculate_path(i)
- self._row_inserted(tuple(child_path))
-
- #my_path = tuple(child_path[0:-1])
- #my_iter = None
- #if my_path:
- # my_iter = self.model.get_iter(my_path)
-
- #l = len(self.child_list)
- #reorder_list = range(l)
- #self.model.rows_reordered(my_path, my_iter, reorder_list)
-
-
- #if i < l - 1:
- # last_path_item = len(path) - 1
- # for n in range(i + 1, l):
- # path[last_path_item] = n
- # self._row_changed(tuple(path))
-
- def find(self, node):
- i = 0
- for path in self.child_list:
- spath = str(path)
- if spath >= node:
- return i
-
- i+=1
-
- return -1
-
- def add(self, data):
- # every node needs to figure this out for themselves
- pass
-
- def _add_child(self, child, data):
- child_path = None
-
- i = self.find(str(child))
- if i == -1:
- self.append(child)
- else:
- objpath = self.child_list[i]
- if str(objpath) == str(child):
- child = objpath
- child.mark_valid()
- child_path = tuple(self._calculate_path(i))
- else:
- self.insert(i, child)
-
- child.add(data)
- if child_path:
- child._row_changed(child_path)
-
- def get_icon_name(self):
- return None
-
- def to_markup_str(self):
- return gobject.markup_escape_text(str(self))
-
- def _sig_list_to_string(self, sig_list):
- result = ''
-
- for sig in sig_list:
- if sig == []:
- print sig_list
- return ''
- result += sig['type']
- if sig['name']:
- result += ' ' + sig['name']
-
- result += ', '
-
- # get rid of the last comma and space before returning
- return result[0:-2]
-
- def _sig_list_to_markup(self, sig_list):
- result = ''
-
- for sig in sig_list:
- result += dbus_utils.sig_to_markup(sig['type'], self.sig_props)
- if sig['name']:
- result += ' <span ' + self.name_props + '>' + sig['name'] + '</span>'
- result += ', '
-
- # get rid of the last comma and space before returning
- return result[0:-2]
-
-
-"""
-Leaf nodes are in a special class because they have special functionality
-The LeafNode class is a helper class which provide common functionality that
-is only of interest to leaf nodes
-"""
-class LeafNode(Node):
- def get_proxy_interface(self, bus, name):
- # it is not strictly necisary to traverse the tree
- # but it future proofs things just in case we move
- # or remove node types
- iface = ''
- obj_path = ''
- node = self.parent
-
- while node is not None:
- if isinstance(node, Interface):
- iface = str(node)
-
- if isinstance(node, ObjectPath):
- obj_path = str(node)
-
- node = node.parent
-
- if not (iface and obj_path):
- raise Exception('introspection tree is corrupt')
-
- proxy = bus.get_object(name, obj_path)
- iface = dbus.Interface(proxy, iface)
-
- return (proxy, iface)
-
-class Method(LeafNode):
- # tree path = (0,x,0,y,0,z)
- def __init__(self, model, parent, method, insig, outsig):
- LeafNode.__init__(self, model, parent)
-
- self.method = method
- self.insig = insig
- self.outsig = outsig
-
- def dbus_call(self, bus, name, *args):
- (proxy, iface) = self.get_proxy_interface(bus, name)
- func = getattr(iface, self.method)
-
- return func(*args)
-
- def to_markup_str(self):
- sig_props = 'foreground="#2E8B57" size="smaller"'
- name_props = ''
- result = self.method + '<span foreground="#FF00FF">(</span>'
- result += self._sig_list_to_markup(self.insig)
- result += '<span foreground="#FF00FF">)</span>'
-
- if self.outsig:
- result += '<span foreground="#A52A2A">' + u' \u27A1 ' + '</span>'
- result += '<span foreground="#FF00FF">(</span>'
- result += self._sig_list_to_markup(self.outsig)
- result += '<span foreground="#FF00FF">)</span>'
-
- return result
-
- def get_icon_name(self):
- return 'dfeet-method'
-
- def __str__(self):
- result = self.method + '('
- result += self._sig_list_to_string(self.insig) + ')'
-
- if self.outsig:
- result += u' \u27A1 (' + self._sig_list_to_string(self.outsig) + ')'
-
- return result
-
-class Signal(LeafNode):
- # tree path = (0,x,0,y,1,z)
- def __init__(self, model, parent, signal, insig):
- self.signal = signal
- self.insig = insig
-
- LeafNode.__init__(self, model, parent)
-
- def dbus_call(self, bus, name, *args):
- # for testing out signals
- # this actually isn't going to work since I
- # can't spoof the sender unless I can own the name
- pass
-
- def get_icon_name(self):
- return 'dfeet-signal'
-
- def to_markup_str(self):
- sig_props = 'foreground="#2E8B57" size="smaller"'
- result = self.signal + '<span foreground="#FF00FF">(</span>'
- result += self._sig_list_to_markup(self.insig)
- result += '<span foreground="#FF00FF">)</span>'
-
- return result
-
- def __str__(self):
- result = self.signal + '('
- result += self._sig_list_to_string(self.insig) + ')'
-
- return result
-
-class Property(LeafNode):
- # tree path = (0,x,0,y,2,z)
- def __init__(self, model, parent, property, sig, access):
- self.property = property
- self.sig = sig
- self.access = access
- self.value = None
-
- LeafNode.__init__(self, model, parent)
-
- def on_selected(self, busname):
- # when selected use the properties interface
- # to read a value if this is a read or
- # readwrite property
- if self.access.startswith('read'):
- bus = busname.get_bus()
- (proxy, iface) = self.get_proxy_interface(bus, busname.get_display_name())
-
- proxy.Get(iface.dbus_interface,
- self.property,
- dbus_interface='org.freedesktop.DBus.Properties',
- reply_handler=self.property_get_handler,
- error_handler=self.property_get_error_handler)
-
-
-
- def property_get_handler(self, value):
- self.value = value
-
- path = tuple(self._calculate_path())
- self._row_changed(path)
-
- def property_get_error_handler(self, e):
- print e
-
- def dbus_call(self, bus, name, *args):
- # for testing out properties
- # this is not implemented yet
- pass
-
- def get_icon_name(self):
- icon = 'dfeet-property'
- if self.access == 'read':
- icon = 'dfeet-read-property'
- elif self.access == 'write':
- icon = 'dfeet-write-property'
- elif self.access == 'readwrite':
- icon = 'dfeet-readwrite-property'
-
- return icon
-
- def to_markup_str(self):
- self.sig_props = 'foreground="#2E8B57" size="smaller"'
- self.name_props = ''
- result = self._sig_list_to_markup(self.sig)
-
- if self.value:
- result += ' = ' + str(self.value)
-
- return result
-
- def __str__(self):
- result = self._sig_list_to_string(self.sig)
- if self.value:
- result += ' = ' + str(self.value)
-
- return result
-
-class MethodLabel(Node):
- # tree path = (0,x,0,y,0)
- def __init__(self, model, parent):
- Node.__init__(self, model, parent)
- self.set_expanded(True)
- self._label = 'Methods'
-
- def add(self, data):
- method_list = data.keys()
- method_list.sort()
- for method_name in method_list:
- method = Method(self.model, self, method_name, data[method_name][0], data[method_name][1])
- self._add_child(method, None)
-
- def get_icon_name(self):
- return 'dfeet-method-category'
-
-
- def to_markup_str(self):
- return '<b>' + gobject.markup_escape_text(self._label) + '</b>'
-
- def __str__(self):
- return self._label
-
-class SignalLabel(Node):
- # tree path = (0,x,0,y,1)
- def __init__(self, model, parent):
- Node.__init__(self, model, parent)
- self.set_expanded(True)
- self._label = 'Signals'
-
- def add(self, data):
- signal_list = data.keys()
- signal_list.sort()
- for signal_name in signal_list:
- signal = Signal(self.model, self, signal_name, data[signal_name][0])
- self._add_child(signal, None)
-
- def get_icon_name(self):
- return 'dfeet-signal-category'
-
- def to_markup_str(self):
- return '<b>' + gobject.markup_escape_text(self._label) + '</b>'
-
- def __str__(self):
- return self._label
-
-class PropertyLabel(Node):
- # tree path = (0,x,0,y,2)
- def __init__(self, model, parent):
- Node.__init__(self, model, parent)
- self.set_expanded(True)
- self._label = 'Properties'
-
- def add(self, data):
- property_list = data.keys()
- property_list.sort()
- for property_name in property_list:
- property = Property(self.model, self, property_name, data[property_name][0], data[property_name][1])
- self._add_child(property, None)
-
- def get_icon_name(self):
- return 'dfeet-property-category'
-
- def to_markup_str(self):
- return '<b>' + gobject.markup_escape_text(self._label) + '</b>'
-
- def __str__(self):
- return self._label
-
-class Interface(Node):
- # tree path = (0,x,0,y)
- def __init__(self, model, parent, interface):
- self.iface = interface
- Node.__init__(self, model, parent)
-
- def add(self, data):
- method_data = data['methods']
- signal_data = data['signals']
- property_data = data['properties']
-
- if method_data:
- methods = MethodLabel(self.model, self)
- self._add_child(methods, method_data)
-
- if signal_data:
- signals = SignalLabel(self.model, self)
- self._add_child(signals, signal_data)
-
- if property_data:
- properties = PropertyLabel(self.model, self)
- self._add_child(properties, property_data)
-
- def __str__(self):
- return self.iface
-
-class InterfaceLabel(Node):
- # tree path = (0,x,0)
- def __init__(self, model, parent):
- Node.__init__(self, model, parent)
- self.set_expanded(True)
-
- self._label='Interfaces'
-
- def add(self, data):
- iface_list = data.keys()
- iface_list.sort()
- for iface in iface_list:
- interface = Interface(self.model, self, iface)
- self._add_child(interface, data[iface])
-
- def to_markup_str(self):
- return '<b>' + gobject.markup_escape_text(self._label) + '</b>'
-
- def __str__(self):
- return self._label
-
-class ObjectPath(Node):
- # tree path = (0,x)
- def __init__(self, model, parent, path):
- self.path = path
-
- Node.__init__(self, model, parent)
-
- def add(self, data):
- iface_data = data['interfaces']
-
- interfaces = InterfaceLabel(self.model, self)
- self._add_child(interfaces, iface_data)
-
- def get_icon_name(self):
- return 'dfeet-object'
-
- def __str__(self):
- return self.path
-
-class ObjectPathLabel(Node):
- # tree path = (0,)
- def __init__(self, model):
- #super(Node, self).__init__(model)
- Node.__init__(self, model)
- self.set_expanded(True)
-
- self._label='Object Paths'
-
- def add(self, data, node):
- obj_path = ObjectPath(self.model, self, node)
-
- self._add_child(obj_path, data)
-
- def to_markup_str(self):
- return '<b>' + gobject.markup_escape_text(self._label) + '</b>'
-
- def __str__(self):
- return self._label
-
-class IntrospectData(Gtk.TreeStore):
- NUM_COL = 3
-
- (SUBTREE_COL,
- DISPLAY_COL,
- ICON_NAME_COL) = range(NUM_COL)
-
- COL_TYPES = (gobject.TYPE_PYOBJECT,
- gobject.TYPE_STRING,
- gobject.TYPE_STRING)
-
- """
- Path Values:
- (0,) - "Object Paths"
- (0,x) - object path
- (0,x,0) - "Interfaces"
- (0,x,0,y) - interface
- (0,x,0,y,0) - "Methods"
- (0,x,0,y,1) - "Signals"
- (0,x,0,y,2) - "Properties"
- (0,x,0,y,0,z) - method signature
- (0,x,0,y,1,z) - signal signature
- (0,x,0,y,1,z) - property signature
-
- """
-
- def __init__(self):
- super(IntrospectData, self).__init__()
-
- self.object_paths = ObjectPathLabel(self)
-
- def append(self, parent_node, data):
- # mark the object path tree invalid if it already
- # exists so we can keep track of state and reap
- # any branches which are not in the new introspect
- # data
- i = self.object_paths.find(parent_node)
- if i >= 0:
- objpath = self.object_paths.child_list[i]
- if str(objpath) == parent_node:
- objpath.mark_tree_invalid()
-
- self.object_paths.add(data, parent_node)
- del(data)
-
- def on_get_flags(self):
- return Gtk.TREE_MODEL_ITERS_PERSIST
-
- def on_get_n_columns(self):
- return self.NUM_COL
-
- def on_get_column_type(self, n):
- return self.COL_TYPES[n]
-
- def on_get_iter(self, path):
- if len(path) == 1:
- if path[0] > 0:
- return None
- return self.object_paths
- else:
- return self.object_paths.on_get_iter(path[1:])
-
- def on_get_path(self, rowref):
- pl = [rowref.get_path_pos()]
- parent = rowref.parent
- while parent:
- pl.insert(0, parent.get_path_pos())
- parent = parent.parent
-
- return tuple(pl)
-
- def on_get_value(self, rowref, column):
- if column == self.SUBTREE_COL:
- return rowref
- elif column == self.DISPLAY_COL:
- return rowref.to_markup_str()
- elif column == self.ICON_NAME_COL:
- return rowref.get_icon_name()
- else:
- raise InvalidColumnError(column)
-
- return None
-
- def on_iter_next(self, rowref):
- try:
- return rowref.get_next()
- except:
- return None
-
- def on_iter_children(self, parent):
- if parent:
- return parent.get_first_child()
-
- return self.object_paths
-
- def on_iter_has_child(self, rowref):
- if rowref.get_first_child():
- return True
- else:
- return False
-
- def on_iter_n_children(self, rowref):
- if rowref:
- return rowref.count_children()
-
- return 1
-
- def on_iter_nth_child(self, parent, n):
- if parent:
- return parent.get_nth_child(n)
-
- if n == 0:
- return self.object_paths
- else:
- return None
-
- def on_iter_parent(self, child):
- return child.parent
-
- def _node_to_str(self, node, prefix=''):
- if not node:
- return ""
-
- if prefix == None:
- prefix = ""
-
- result = prefix + str(node) + '\n'
- for child in node.child_list:
- result += self._node_to_str(child, prefix + '\t')
-
- return result
-
- def __str__(self):
-
- return self._node_to_str(self.object_paths)
-
diff --git a/dfeet/introspection.py b/dfeet/introspection.py
new file mode 100644
index 0000000..a37a811
--- /dev/null
+++ b/dfeet/introspection.py
@@ -0,0 +1,229 @@
+# -*- coding: utf-8 -*-
+
+from gi.repository import GObject, Gdk, GdkPixbuf, Gtk, Gio, Pango, GLib
+import dbus_utils
+from _ui.executemethoddialog import ExecuteMethodDialog
+import time
+
+from _ui.uiloader import UILoader
+
+from introspection_helper import DBusNode, DBusInterface, DBusProperty, DBusSignal, DBusMethod
+
+
+class AddressInfo():
+ """
+ class to handle information about a name (eg "org.freedesktop.NetworkManager")
+ on a given address (eg Gio.BusType.SYSTEM or unix:path=/var/run/dbus/system_bus_socket)
+ """
+ def __init__(self, address, name, connection_is_bus=True):
+ self.address = address # can be Gio.BusType.SYSTEM or Gio.BusType.SYSTEM or an other address
+ self.name = name
+ self.connection_is_bus = connection_is_bus # is it a bus or a p2p connection?
+ self.introspect_time = -1 # time needed to introspect the given bus name (in seconds)
+
+ #setup UI
+ ui = UILoader(UILoader.UI_INTROSPECTION)
+ self.introspect_box = ui.get_root_widget()
+ self.tree_model = ui.get_widget('treestore')
+ self.treeview = ui.get_widget('treeview')
+ button_reload = ui.get_widget('button_reload')
+ self.label_name = ui.get_widget('label_name')
+ self.label_unique_name = ui.get_widget('label_unique_name')
+ self.label_address = ui.get_widget('label_address')
+ cr_name = Gtk.CellRendererText()
+ col_name = Gtk.TreeViewColumn()
+ col_name.pack_start(cr_name, True)
+ col_name.add_attribute(cr_name, 'markup', 0)
+ self.treeview.append_column(col_name)
+
+ #connect signals
+ button_reload.connect("clicked", self.__on_button_reload_clicked, self)
+ self.treeview.connect('cursor-changed',
+ self.tree_view_cursor_changed_cb)
+ self.treeview.connect('row-activated',
+ self.tree_view_row_activated_cb)
+
+ if self.connection_is_bus:
+ #we expect a bus connection
+ if self.address == Gio.BusType.SYSTEM or self.address == Gio.BusType.SESSION:
+ self.connection = Gio.bus_get_sync(self.address, None)
+ self.label_address.set_text(Gio.dbus_address_get_for_bus_sync(self.address, None))
+ elif Gio.dbus_is_supported_address(self.address) == True:
+ self.connection = Gio.DBusConnection.new_for_address_sync(self.address,
+ Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT | Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION,
+ None, None)
+ self.label_address.set_text(self.address)
+ else:
+ self.connection = None
+ raise Exception("Invalid bus address '%'" % (self.address))
+ else:
+ #we have a peer-to-peer connection
+ if Gio.dbus_is_supported_address(self.address) == True:
+ self.connection = Gio.DBusConnection.new_for_address_sync(self.address,
+ Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT,
+ None, None)
+ self.label_address.set_text(self.address)
+ else:
+ self.connection = None
+ raise Exception("Invalid p2p address '%'" % (self.address))
+
+ #start processing data
+ self.introspect()
+ self.treeview.expand_all() #FIXME: only good for testing!
+
+ def tree_view_cursor_changed_cb(self, treeview):
+ """ do something when a row is selected """
+ selection = self.treeview.get_selection()
+ if selection:
+ model, iter = selection.get_selected()
+ if not iter:
+ return
+
+ node_obj = model.get(iter, 1)[0]
+ #print "NODE: %s" % (node_obj)
+
+ def tree_view_row_activated_cb(self, treeview, path, view_column):
+ model = treeview.get_model()
+ iter = model.get_iter(path)
+
+ obj = model.get_value(iter, 1)
+
+ if isinstance(obj, DBusMethod):
+ #execute the selected method
+ dialog = ExecuteMethodDialog(self.connection, self.connection_is_bus, self.name, obj)
+ dialog.run()
+ elif isinstance(obj, DBusProperty):
+ #update the selected property (TODO: do this async)
+ proxy = Gio.DBusProxy.new_sync(self.connection,
+ Gio.DBusProxyFlags.NONE,
+ None,
+ self.name,
+ obj.object_path,
+ "org.freedesktop.DBus.Properties", None)
+ args = GLib.Variant('(ss)', (obj.iface_info.name, obj.property_info.name))
+ result = proxy.call_sync("Get", args, 0, -1, None)
+ #update the object value so markup string is calculated correct
+ obj.value = result[0]
+ #set new markup string
+ model[iter][0] = obj.markup_str
+ else:
+ if treeview.row_expanded(path):
+ treeview.collapse_row(path)
+ else:
+ treeview.expand_row(path, False)
+
+
+ def introspect(self):
+ """ introspect the given bus name and update the tree model """
+ #cleanup current tree model
+ self.tree_model.clear()
+ #start introspection and measure introspection time
+ introspect_start = time.time()
+ self.__dbus_node_introspect(self.name, "/")
+ self.introspect_time = time.time() - introspect_start
+ #update name, unique name, ...
+ self.label_name.set_text(self.name)
+ try:
+ self.label_unique_name.set_text(self.connection.get_unique_name())
+ except:
+ pass
+
+
+ def __on_button_reload_clicked(self, widget, address_info):
+ """ reload the introspection data """
+ address_info.introspect()
+ print "needed %.3f s to introspect name '%s'" % (address_info.introspect_time, address_info.name)
+
+
+ def __dbus_node_introspect(self, name, object_path):
+ """ iterate over the given object_path and introspect the path recursive """
+ tree_iter = None
+ if self.connection_is_bus:
+ proxy = Gio.DBusProxy.new_sync(self.connection,
+ Gio.DBusProxyFlags.NONE,
+ None,
+ name,
+ object_path,
+ 'org.freedesktop.DBus.Introspectable', None)
+ node_info = Gio.DBusNodeInfo.new_for_xml(proxy.Introspect())
+ else:
+ res = self.connection.call_sync(None, object_path, 'org.freedesktop.DBus.Introspectable', 'Introspect', None, GLib.VariantType.new("(s)"), Gio.DBusCallFlags.NONE, -1, None)
+ node_info = Gio.DBusNodeInfo.new_for_xml(res[0])
+
+ #create a GObject node and add to tree-model
+ if len(node_info.interfaces) > 0:
+ node_obj = DBusNode(name, object_path, node_info)
+ tree_iter = self.tree_model.append(tree_iter, ["%s" % object_path, node_obj])
+ #tree_iter = self.tree_model.append(tree_iter, ["Hallo", None])
+
+ #append interfaces to tree model
+ if len(node_info.interfaces) > 0:
+ name_iter = self.tree_model.append(tree_iter, ["<b>Interfaces</b>", None])
+ for iface in node_info.interfaces:
+ iface_obj = DBusInterface(node_obj, iface)
+ iface_iter = self.tree_model.append(name_iter, ["%s" % iface.name, iface_obj])
+ #interface methods
+ if len(iface.methods) > 0:
+ iface_methods_iter = self.tree_model.append(iface_iter, ["<b>Methods</b>", None])
+ for iface_method in iface.methods:
+ method_obj = DBusMethod(iface_obj, iface_method)
+ self.tree_model.append(iface_methods_iter, ["%s" % method_obj.markup_str, method_obj])
+ #interface signals
+ if len(iface.signals) > 0:
+ iface_signals_iter = self.tree_model.append(iface_iter, ["<b>Signals</b>", None])
+ for iface_signal in iface.signals:
+ signal_obj = DBusSignal(iface_obj, iface_signal)
+ self.tree_model.append(iface_signals_iter, ["%s" % signal_obj.markup_str, signal_obj])
+ #interface properties
+ if len(iface.properties) > 0:
+ iface_properties_iter = self.tree_model.append(iface_iter, ["<b>Properties</b>", None])
+ for iface_property in iface.properties:
+ property_obj = DBusProperty(iface_obj, iface_property)
+ self.tree_model.append(iface_properties_iter, ["%s" % property_obj.markup_str, property_obj])
+ #interface annotations #FIXME: add Annotation object!!!
+ if len(iface.annotations) > 0:
+ iface_annotations_iter = self.tree_model.append(iface_iter, ["<b>Annotations</b>", None])
+ for iface_annotation in iface.annotations:
+ self.tree_model.append(iface_annotations_iter, ["%s" % iface_annotation.name, iface_annotation])
+
+
+ for node in node_info.nodes:
+ #node_iter = self.tree_model.append(tree_iter, [node.path, node])
+ if object_path == "/":
+ object_path = ""
+ object_path_new = object_path + "/" + node.path
+ self.__dbus_node_introspect(name, object_path_new)
+
+
+
+if __name__ == "__main__":
+ """ for debugging """
+ import sys
+ import argparse
+
+ parser = argparse.ArgumentParser(description='introspect a given dbus address and name')
+ parser.add_argument('-p', '--p2p', action='store_true', default=False)
+ parser.add_argument('addr')
+ parser.add_argument('name')
+ p = parser.parse_args()
+
+ if p.addr.lower() == 'system':
+ addr = Gio.BusType.SYSTEM
+ elif p.addr.lower() == 'session':
+ addr = Gio.BusType.SESSION
+ else:
+ addr = p.addr
+
+
+ name = p.name
+ ai = AddressInfo(addr, name, not p.p2p)
+
+ win = Gtk.Window()
+ win.connect("delete-event", Gtk.main_quit)
+ win.set_default_size(1024, 768)
+ win.add(ai.introspect_box)
+ win.show_all()
+ try:
+ Gtk.main()
+ except (KeyboardInterrupt, SystemExit):
+ Gtk.main_quit()
diff --git a/dfeet/introspection_helper.py b/dfeet/introspection_helper.py
new file mode 100644
index 0000000..d7214eb
--- /dev/null
+++ b/dfeet/introspection_helper.py
@@ -0,0 +1,218 @@
+# -*- coding: utf-8 -*-
+
+from gi.repository import GObject, Gio, GLib
+import dbus_utils
+
+
+def args_signature_markup(arg_signature):
+ return '<small><span foreground="#2E8B57">%s</span></small>' % (arg_signature)
+
+def args_name_markup(arg_name):
+ return '<small><span foreground="#000000">%s</span></small>' % (arg_name)
+
+
+
+class DBusNode(GObject.GObject):
+ """ object to represent a DBus Node (object path) """
+ def __init__(self, name, object_path, node_info):
+ GObject.GObject.__init__(self)
+ self.__name = name
+ self.__object_path = object_path
+ self.__node_info = node_info # Gio.GDBusNodeInfo object
+
+ def __repr__(self):
+ return u"Name: %s ; ObjPath: %s ; NodeInfo: %s" % (self.name, self.object_path, self.node_info)
+
+ @property
+ def name(self):
+ return self.__name
+
+ @property
+ def object_path(self):
+ return self.__object_path
+
+ @property
+ def node_info(self):
+ return self.__node_info
+
+
+class DBusInterface(DBusNode):
+ """ object to represent a DBus Interface """
+ def __init__(self, dbus_node_obj, iface_info):
+ DBusNode.__init__(self, dbus_node_obj.name, dbus_node_obj.object_path, dbus_node_obj.node_info)
+ self.__iface_info = iface_info # Gio.GDBusInterfaceInfo object
+
+ def __repr__(self):
+ return u"iface '%s' on node '%s'" % (self.iface_info.name, self.node_info.path)
+
+ @property
+ def iface_info(self):
+ return self.__iface_info
+
+
+class DBusProperty(DBusInterface):
+ """ object to represent a DBus Property """
+ def __init__(self, dbus_iface_obj, property_info):
+ DBusInterface.__init__(self, dbus_iface_obj, dbus_iface_obj.iface_info)
+ self.__property_info = property_info # Gio.GDBusPropertyInfo object
+ self.__value = None #the value
+
+ def __repr__(self):
+ sig = dbus_utils.sig_to_string(self.property_info.signature)
+ return u"%s %s (%s)" % (sig, self.property_info.name, self.property_info.flags)
+
+ @property
+ def property_info(self):
+ return self.__property_info
+
+ @property
+ def value(self):
+ return self.__value
+
+ @value.setter
+ def value(self, new_val):
+ self.__value = new_val
+
+
+ @property
+ def markup_str(self):
+ sig = dbus_utils.sig_to_string(self.property_info.signature)
+ readwrite = list()
+ if self.readable:
+ readwrite.append("read")
+ if self.writable:
+ readwrite.append("write")
+ s = "%s %s <small>(%s)</small>" % (args_signature_markup(sig), args_name_markup(self.property_info.name), " / ".join(readwrite))
+ if self.value:
+ s += " = %s" % (self.value)
+ return s
+
+ @property
+ def readable(self):
+ if int(self.property_info.flags) == int(Gio.DBusPropertyInfoFlags.READABLE) or int(self.property_info.flags) == (int(Gio.DBusPropertyInfoFlags.WRITABLE | Gio.DBusPropertyInfoFlags.READABLE)):
+ return True
+ else:
+ return False
+
+ @property
+ def writable(self):
+ if int(self.property_info.flags) == int(Gio.DBusPropertyInfoFlags.WRITABLE) or int(self.property_info.flags) == (int(Gio.DBusPropertyInfoFlags.WRITABLE | Gio.DBusPropertyInfoFlags.READABLE)):
+ return True
+ else:
+ return False
+
+
+class DBusSignal(DBusInterface):
+ """ object to represent a DBus Signal """
+ def __init__(self, dbus_iface_obj, signal_info):
+ DBusInterface.__init__(self, dbus_iface_obj, dbus_iface_obj.iface_info)
+ self.__signal_info = signal_info #Gio.GDBusSignalInfo object
+
+ def __repr__(self):
+ return u"%s" % (self.signal_info.name)
+
+ @property
+ def signal_info(self):
+ return self.__signal_info
+
+ @property
+ def args(self):
+ args = list()
+ for arg in self.signal_info.args:
+ sig = dbus_utils.sig_to_string(arg.signature)
+ args.append({'signature': sig, 'name': arg.name})
+ return args
+
+ @property
+ def args_markup_str(self):
+ result = ''
+ result += '<span foreground="#FF00FF">(</span>'
+ result += ', '.join('%s' % (args_signature_markup(arg['signature'])) for arg in self.args)
+ result += '<span foreground="#FF00FF">)</span>'
+ return result
+
+ @property
+ def markup_str(self):
+ return "%s %s" % (self.signal_info.name, self.args_markup_str)
+
+
+class DBusMethod(DBusInterface):
+ """ object to represent a DBus Method """
+ def __init__(self, dbus_iface_obj, method_info):
+ DBusInterface.__init__(self, dbus_iface_obj, dbus_iface_obj.iface_info)
+ self.__method_info = method_info #Gio.GDBusMethodInfo object
+
+ def __repr__(self):
+ return u"%s(%s) ↦ %s (%s)" % (self.method_info.name, self.in_args_str, self.out_args_str, DBusInterface.__repr__(self))
+
+ @property
+ def method_info(self):
+ return self.__method_info
+
+ @property
+ def iface_info(self):
+ return super(DBusMethod, self).iface_info
+
+ @property
+ def name(self):
+ return super(DBusMethod, self).name
+
+ @property
+ def object_path(self):
+ return super(DBusMethod, self).object_path
+
+ @property
+ def node_info(self):
+ return super(DBusMethod, self).node_info
+
+ @property
+ def markup_str(self):
+ return u"%s %s <b>↦</b> %s" % (self.method_info.name, self.in_args_markup_str, self.out_args_markup_str)
+
+ @property
+ def in_args(self):
+ in_args = list()
+ for in_arg in self.method_info.in_args:
+ sig = dbus_utils.sig_to_string(in_arg.signature)
+ in_args.append({'signature': sig, 'name': in_arg.name})
+ return in_args
+
+ @property
+ def out_args(self):
+ out_args = list()
+ for out_arg in self.method_info.out_args:
+ sig = dbus_utils.sig_to_string(out_arg.signature)
+ out_args.append({'signature': sig, 'name': out_arg.name})
+ return out_args
+
+ @property
+ def in_args_str(self):
+ result = u''
+ for arg in self.in_args:
+ result += "%s %s, " % (arg['signature'], arg['name'])
+
+ return result[0:-2]
+
+ @property
+ def out_args_str(self):
+ result = u''
+ for arg in self.out_args:
+ result += "%s %s, " % (arg['signature'], arg['name'])
+
+ return result[0:-2]
+
+ def __args_markup_str(self, args):
+ """ markup a given list of args """
+ result = ''
+ result += '<span foreground="#FF00FF">(</span>'
+ result += ', '.join('%s %s' % (args_signature_markup(arg['signature']), args_name_markup(arg['name'])) for arg in args)
+ result += '<span foreground="#FF00FF">)</span>'
+ return result
+
+ @property
+ def in_args_markup_str(self):
+ return self.__args_markup_str(self.in_args)
+
+ @property
+ def out_args_markup_str(self):
+ return self.__args_markup_str(self.out_args)
diff --git a/tests/tests.py b/tests/tests.py
new file mode 100755
index 0000000..bb58ffd
--- /dev/null
+++ b/tests/tests.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+import sys, os
+sys.path.insert(0, os.path.abspath(os.path.join(__file__, "../../")))
+
+from gi.repository import Gtk, Gio, GLib
+from dfeet.introspection import AddressInfo
+from dfeet.introspection_helper import DBusNode, DBusInterface, DBusProperty, DBusSignal, DBusMethod
+import unittest
+import time
+
+XML = """
+<node>
+ <interface name='org.gnome.d-feet.TestInterface'>
+ <method name='HelloWorld'>
+ <arg type='s' name='greeting' direction='in'/>
+ <arg type='s' name='response' direction='out'/>
+ </method>
+ <property name="TestString" type="s" access="readwrite"/>
+ <property name="TestBool" type="b" access="read"/>
+ <signal name="TestSignal">
+ <arg name="SigString" type="s"/>
+ <arg name="SigBool" type="b"/>
+ </signal>
+ </interface>
+</node>
+"""
+
+class IntrospectionHelperTest(unittest.TestCase):
+ """ tests for the introspection helper classes """
+ def setUp(self):
+ self.name = "org.gnome.d-feet"
+ self.object_path = "/org/gnome/d-feet"
+ self.node_info = Gio.DBusNodeInfo.new_for_xml(XML)
+
+ def test_dbus_node_info(self):
+ """ test DBusNode class """
+ obj_node = DBusNode(self.name, self.object_path, self.node_info)
+ self.assertEqual(obj_node.name, self.name)
+ self.assertEqual(obj_node.object_path, self.object_path)
+ self.assertEqual(len(obj_node.node_info.interfaces), 1)
+
+ def test_dbus_interface(self):
+ """ test DBusInterface class """
+ obj_node = DBusNode(self.name, self.object_path, self.node_info)
+ obj_iface = DBusInterface(obj_node, obj_node.node_info.interfaces[0])
+ self.assertEqual(obj_iface.name, self.name)
+ self.assertEqual(obj_iface.object_path, self.object_path)
+ self.assertEqual(len(obj_iface.iface_info.methods), 1)
+ self.assertEqual(len(obj_iface.iface_info.properties), 2)
+ self.assertEqual(len(obj_iface.iface_info.signals), 1)
+
+ def test_dbus_property(self):
+ """ test DBusProperty class """
+ obj_node = DBusNode(self.name, self.object_path, self.node_info)
+ obj_iface = DBusInterface(obj_node, obj_node.node_info.interfaces[0])
+ obj_prop = DBusProperty(obj_iface, obj_iface.iface_info.properties[0])
+ self.assertEqual(obj_prop.name, self.name)
+ self.assertEqual(obj_prop.object_path, self.object_path)
+
+ def test_dbus_signal(self):
+ """ test DBusSignal class """
+ obj_node = DBusNode(self.name, self.object_path, self.node_info)
+ obj_iface = DBusInterface(obj_node, obj_node.node_info.interfaces[0])
+ obj_sig = DBusSignal(obj_iface, obj_iface.iface_info.signals[0])
+ self.assertEqual(obj_sig.name, self.name)
+ self.assertEqual(obj_sig.object_path, self.object_path)
+
+
+class AddressInfoTest(unittest.TestCase):
+ """ tests for the AddressInfo class and the introspection stuff """
+
+ def test_system_bus(self):
+ """ introspect a name on the system bus """
+ ai = AddressInfo(Gio.BusType.SYSTEM, "org.freedesktop.DBus")
+
+ def test_session_bus(self):
+ """ introspect a name on the session bus """
+ return
+ ai = AddressInfo(Gio.BusType.SESSION, "org.freedesktop.DBus")
+
+ def test_other_bus(self):
+ """ test another bus """
+ return
+ sysbus_addr = os.getenv("DBUS_SYSTEM_BUS_ADDRESS")
+ ai = AddressInfo(sysbus_addr, "org.freedesktop.DBus")
+ #TODO: create another bus and test with the other bus
+
+ @unittest.skip("TODO:peer to peer test not implemented")
+ def test_peer_to_peer(self):
+ """ test a p2p connection """
+ #TODO: setup a gdbus server and test a peer to peer connection
+ #(see http://developer.gnome.org/gio/unstable/GDBusServer.html#gdbus-peer-to-peer)
+ pass
+
+if __name__ == "__main__":
+ #FIXME: this is copied from the file "f-deet"
+ ENV_PATHS = {"DFEET_DATA_PATH" : "ui/",
+ "DFEET_IMAGE_PATH" : "ui/",
+ "DFEET_LOCALE_PATH" : "locale/",
+ "DFEET_HELP_PATH" : "/usr/share/gnome/dfeet/"
+ }
+ for var, path in ENV_PATHS.iteritems():
+ os.environ.setdefault(var, path)
+
+ #run tests
+ unittest.main()
diff --git a/tests/tests.py~ b/tests/tests.py~
new file mode 100755
index 0000000..9a49ded
--- /dev/null
+++ b/tests/tests.py~
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+import sys, os
+sys.path.insert(0, os.path.abspath(os.path.join(__file__, "../../")))
+
+from gi.repository import Gtk, Gio, GLib
+from dfeet.gdbus_introspector import BusNameInfo
+import threading
+import unittest
+import time
+
+
+class DBusServer:
+ """ a dbus server for testing. Sever runs inside a thread """
+ XML = '''
+<node>
+ <interface name='de.toabctl.Demo.Hello'>
+ <method name='hello'>
+ <arg type='s' name='ping' direction='in'/>
+ <arg type='s' name='pong' direction='out'/>
+ </method>
+ </interface>
+</node>'''
+ def __init__(self, addr):
+ self.addr = addr
+ self.server = Gio.DBusServer.new_sync(self.addr,
+ Gio.DBusServerFlags.AUTHENTICATION_ALLOW_ANONYMOUS,
+ Gio.dbus_generate_guid(),
+ None, None)
+ self.server.start()
+ self.server.connect("new-connection", self.new_connection_cb, self)
+ self.loop = GLib.MainLoop()
+ self.vtable = Gio.DBusInterfaceVTable()
+ self.vtable.method_call(self.handle_method_call_cb)
+ self.vtable.get_property(None)
+ self.vtable.set_property(None)
+
+ def handle_method_call_cb(self, connection, sender, object_path, interface_name, method_name, parameters, invocation, user_data):
+ print "method call"
+ if method_name == "hello":
+ ret = GLib.Variant(("s"), ("Adios"))
+ involcation.return_value(ret)
+
+ def new_connection_cb(self, server, connection, user_data):
+ print "new connection"
+ connection.register_object("/de/toabctl/Demo/", DBusServer.XML,
+ self.vtable, None, None)
+
+ def start(self):
+ self.loop.run()
+
+ def quit(self):
+ self.server.stop()
+ self.loop.quit()
+
+class Introspector(unittest.TestCase):
+ """ tests for gdbus_introspector.py """
+
+ def test_system_bus(self):
+ return
+ bni = BusNameInfo(Gio.BusType.SYSTEM, "org.freedesktop.DBus")
+
+ def test_session_bus(self):
+ return
+ bni = BusNameInfo(Gio.BusType.SESSION, "org.freedesktop.DBus")
+
+if __name__ == '__main__':
+ #FIXME: this is copied from the file "f-deet"
+ ENV_PATHS = {"DFEET_DATA_PATH" : "ui/",
+ "DFEET_IMAGE_PATH" : "ui/",
+ "DFEET_LOCALE_PATH" : "locale/",
+ "DFEET_HELP_PATH" : "/usr/share/gnome/dfeet/"
+ }
+ for var, path in ENV_PATHS.iteritems():
+ os.environ.setdefault(var, path)
+
+ #run tests
+ #unittest.main()
+ s = DBusServer("unix:abstract=myaddr")
+ s.start()
diff --git a/tests/uifile_tests.py b/tests/uifile_tests.py
deleted file mode 100755
index ca2294e..0000000
--- a/tests/uifile_tests.py
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env python
-from gi.repository import Gtk
-
-main_ui = Gtk.Builder()
-main_ui.add_from_file("../ui/default-actiongroup.ui")
-main_ui.add_from_file("../ui/mainwindow.ui")
-
-win = main_ui.get_object("appwindow1")
-win.show_all()
-
-filterbox_ui = Gtk.Builder()
-filterbox_ui.add_from_file("../ui/filterbox.ui")
-
-filterbox_win = Gtk.Window(Gtk.WindowType.TOPLEVEL)
-filterbox = filterbox_ui.get_object("filterbox_table1")
-filterbox_win.add(filterbox)
-filterbox_win.show_all()
-
-introspectview_ui = Gtk.Builder()
-introspectview_ui.add_from_file("../ui/introspectview.ui")
-
-introspectview_win = Gtk.Window(Gtk.WindowType.TOPLEVEL)
-introspectview = introspectview_ui.get_object("introspectview_table1")
-introspectview_win.add(introspectview)
-introspectview_win.show_all()
-
-executedialog_ui = Gtk.Builder()
-executedialog_ui.add_from_file("../ui/executedialog.ui")
-
-executedialog_win = executedialog_ui.get_object("executedialog1")
-executedialog_win.show_all()
-
-Gtk.main()
diff --git a/ui/addconnectiondialog.ui b/ui/addconnectiondialog.ui
index f1096dd..4806dcb 100644
--- a/ui/addconnectiondialog.ui
+++ b/ui/addconnectiondialog.ui
@@ -1,58 +1,77 @@
-<?xml version="1.0" standalone="no"?>
-<!--*- mode: xml -*-->
+<?xml version="1.0" encoding="UTF-8"?>
<interface>
+ <!-- interface-requires gtk+ 3.0 -->
<object class="GtkDialog" id="add_connection_dialog1">
+ <property name="can_focus">False</property>
<property name="border_width">5</property>
- <property name="default_height">50</property>
+ <property name="title" translatable="yes" context="yes">Add a Connection</property>
<property name="default_width">480</property>
+ <property name="default_height">50</property>
<property name="destroy_with_parent">True</property>
- <property name="has_separator">False</property>
- <property name="title" context="yes" translatable="yes">Add a Connection</property>
<property name="type_hint">normal</property>
<child internal-child="vbox">
- <object class="GtkVBox" id="dialog1-vbox">
- <property name="border_width">2</property>
+ <object class="GtkBox" id="dialog1-vbox">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="label1">
- <property name="label" context="yes" translatable="yes">&lt;b&gt;Bus Address: &lt;/b&gt;</property>
- <property name="use_markup">True</property>
<property name="visible">True</property>
- <property name="xalign">0.0</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes">See http://dbus.freedesktop.org/doc/dbus-specification.html#addresses</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes" context="yes">Address:</property>
</object>
<packing>
<property name="expand">False</property>
- <property name="fill">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkComboBoxEntry" id="address_comboentry1">
- <property name="items">Session Bus</property>
- <property name="visible">True</property>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
+ <placeholder/>
</child>
</object>
<packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
<property name="padding">5</property>
- <property name="position">1</property>
+ <property name="position">0</property>
</packing>
</child>
<child internal-child="action_area">
- <object class="GtkHButtonBox" id="dialog1-action_area">
- <property name="border_width">5</property>
+ <object class="GtkButtonBox" id="dialog1-action_area">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="layout_style">end</property>
- <property name="spacing">6</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_status">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
+ <property name="fill">True</property>
<property name="pack_type">end</property>
+ <property name="position">2</property>
</packing>
</child>
</object>
diff --git a/ui/buswatch.ui b/ui/buswatch.ui
new file mode 100644
index 0000000..fdba11a
--- /dev/null
+++ b/ui/buswatch.ui
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkListStore" id="liststore_buswatch">
+ <columns>
+ <!-- column-name bus_name_obj -->
+ <column type="GObject"/>
+ <!-- column-name bus_name_pid -->
+ <column type="guint"/>
+ <!-- column-name bus_name_unique -->
+ <column type="gchararray"/>
+ <!-- column-name bus_name_cmdline -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkPaned" id="paned_buswatch">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkBox" id="box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Filter:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entry_filter">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="treeview_buswatch">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="halign">start</property>
+ <property name="valign">start</property>
+ <property name="model">liststore_buswatch</property>
+ <property name="search_column">2</property>
+ <property name="tooltip_column">2</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn_unique_bus_name">
+ <property name="title" translatable="yes">unique bus name</property>
+ <property name="clickable">True</property>
+ <property name="sort_indicator">True</property>
+ <property name="sort_column_id">2</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext_unique_bus_name"/>
+ <attributes>
+ <attribute name="text">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="grid_bus_name_info">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Command line:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_bus_name_selected_cmdline">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">char</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Process ID:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_bus_name_selected_pid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0.52999997138977051</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Name:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_bus_name_selected_name">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="pixbuf">dfeet-icon.png</property>
+ </object>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/ui/default-actiongroup.ui b/ui/default-actiongroup.ui
deleted file mode 100644
index f35a955..0000000
--- a/ui/default-actiongroup.ui
+++ /dev/null
@@ -1,99 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<interface>
- <object class="GtkUIManager" id="default-uiman">
- <child>
- <object class="GtkActionGroup" id="DefaultActions">
- <child>
- <object class="GtkAction" id="file_toplevel">
- <property name="label" translatable="yes">_File</property>
- </object>
- </child>
- <child>
- <object class="GtkAction" id="add_bus_address">
- <property name="name">add_bus_address</property>
- <property name="label" translatable="yes">Connect to _Other Bus...</property>
- <property name="short_label" translatable="yes">Bus...</property>
- <property name="tooltip" translatable="yes">Add a bus tab using an address</property>
- <property name="stock_id">gtk-connect</property>
- <signal handler="add_bus_address" name="activate"/>
- </object>
- </child>
- <child>
- <object class="GtkAction" id="reconnect_current_bus">
- <property name="name">reconnect_current_bus</property>
- <property name="label" translatable="yes">Reconnect current Bus...</property>
- <property name="short_label" translatable="yes">Reconnect</property>
- <property name="tooltip" translatable="yes">Reconnect the bus of the current tab address</property>
- <property name="sensitive">False</property>
- <property name="stock_id">gtk-refresh</property>
- <signal handler="reconnect_current_bus" name="activate"/>
- </object>
- </child>
- <child>
- <object class="GtkAction" id="add_session_bus">
- <property name="name">add_session_bus</property>
- <property name="label" translatable="yes">Connect to S_ession Bus</property>
- <property name="short_label" translatable="yes">Session</property>
- <property name="tooltip" translatable="yes">Add a session bus tab</property>
- <signal handler="add_session_bus" name="activate"/>
- </object>
- </child>
- <child>
- <object class="GtkAction" id="add_system_bus">
- <property name="name">add_system_bus</property>
- <property name="label" translatable="yes">Connect to S_ystem Bus</property>
- <property name="short_label" translatable="yes">System</property>
- <property name="tooltip" translatable="yes">Add a system bus tab</property>
- <signal handler="add_system_bus" name="activate"/>
- </object>
- </child>
- <child>
- <object class="GtkAction" id="execute_method">
- <property name="name">execute_method</property>
- <property name="label" translatable="yes">E_xecute Method</property>
- <property name="short_label" translatable="yes">Execute</property>
- <property name="tooltip" translatable="yes">Execute the selected method</property>
- <property name="sensitive">False</property>
- <property name="stock_id">gtk-execute</property>
- <signal handler="execute_method" name="activate"/>
- </object>
- </child>
- <child>
- <object class="GtkAction" id="quit">
- <property name="name">quit</property>
- <property name="label" translatable="yes">_Quit</property>
- <property name="tooltip" translatable="yes">Quit D-Feet</property>
- <property name="stock_id">gtk-quit</property>
- <signal handler="quit" name="activate"/>
- </object>
- </child>
- </object>
- </child>
- <ui>
- <menubar name="menubar1">
- <menu action="file_toplevel">
- <menuitem name="ConnSessionMenu" action="add_session_bus" />
- <menuitem name="ConnSystemMenu" action="add_system_bus" />
- <menuitem name="ConnOtherMenu" action="add_bus_address" />
- <menuitem name="QuitMenu" action="quit" />
- </menu>
- </menubar>
- <toolbar name="toolbar1">
- <toolitem name="ConnOtherTool" action="add_bus_address">
- <!-- FIXME: This doesn't work and needs to be fixed in Gtk
- so that the GtkAction can specify using GtkToolMenuButton
- instead of just a regular GtkToolButton
- <menu action="file_toplevel">
- <menuitem name="ConnSessionMenu" action="add_session_bus" />
- <menuitem name="ConnSystemMenu" action="add_system_bus" />
- </menu>
- -->
- </toolitem>
- <toolitem name="ConnReconnect" action="reconnect_current_bus"/>
- <separator/>
- <toolitem name="ExecuteMethod" action="execute_method"/>
- </toolbar>
- </ui>
- </object>
-</interface>
diff --git a/ui/executedialog.ui b/ui/executedialog.ui
index 92b8c0c..06c3a89 100644
--- a/ui/executedialog.ui
+++ b/ui/executedialog.ui
@@ -1,146 +1,446 @@
-<?xml version="1.0"?>
-
+<?xml version="1.0" encoding="UTF-8"?>
<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="lower">1</property>
+ <property name="upper">100</property>
+ <property name="value">1</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
<object class="GtkDialog" id="executedialog1">
- <property name="allow_shrink">True</property>
- <property name="default_height">400</property>
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes" context="yes">Execute D-Bus Method</property>
<property name="default_width">320</property>
+ <property name="default_height">400</property>
<property name="destroy_with_parent">True</property>
- <property name="title" context="yes" translatable="yes">Execute D-Bus Method</property>
- <!--<property name="type_hint">normal</property>-->
- <signal handler="execute_dialog_close_cb" name="close"/>
+ <property name="type_hint">normal</property>
+ <signal name="close" handler="execute_dialog_close_cb" swapped="no"/>
<child internal-child="vbox">
- <object class="GtkVBox" id="dialog1-vbox">
- <property name="border_width">2</property>
+ <object class="GtkBox" id="dialog1-vbox">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog1-action_area">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="closebutton1">
+ <property name="label" context="yes">gtk-close</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ <signal name="clicked" handler="execute_dialog_close_cb" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="executebutton1">
+ <property name="label" translatable="yes" context="yes">_Execute</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="is_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="execute_dbus_method_cb" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
<child>
<object class="GtkVBox" id="vbox3">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLabel" id="label_method_name">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="ypad">5</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">&lt;b&gt;Method name:&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">&lt;b&gt;Object Path:&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">&lt;b&gt;Interface:&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_object_path">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_interface">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
<child>
- <object class="GtkLabel" id="commandlabel1">
- <property name="label" context="yes" translatable="yes">Execute i.c on object path o</property>
+ <object class="GtkLabel" id="label4">
<property name="visible">True</property>
- <property name="xalign">0.0</property>
- <property name="ypad">5</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="margin_top">10</property>
+ <property name="label" translatable="yes">&lt;b&gt;Method input&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
+ <property name="position">1</property>
</packing>
</child>
<child>
- <object class="GtkFrame" id="frame1">
- <property name="label" context="yes" translatable="yes">Parameters (in python syntax)</property>
- <property name="shadow">none</property>
- <property name="shadow_type">none</property>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
<child>
- <object class="GtkScrolledWindow" id="scrolledwindow1">
- <property name="hscrollbar_policy">never</property>
- <property name="shadow_type">in</property>
+ <object class="GtkTextView" id="parametertextview1">
<property name="visible">True</property>
- <property name="vscrollbar_policy">automatic</property>
- <child>
- <object class="GtkTextView" id="parametertextview1">
- <property name="is_focus">True</property>
- <property name="visible">True</property>
- <property name="wrap_mode">word</property>
- </object>
- </child>
+ <property name="can_focus">True</property>
</object>
</child>
</object>
<packing>
- <property name="position">1</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="margin_top">10</property>
+ <property name="yalign">0.49000000953674316</property>
+ <property name="xpad">1</property>
+ <property name="label" translatable="yes">&lt;b&gt;Method output&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame2">
- <property name="label" context="yes" translatable="yes">Output</property>
- <property name="shadow">none</property>
- <property name="shadow_type">none</property>
<property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
<child>
<object class="GtkNotebook" id="notebook1">
- <property name="tab_pos">bottom</property>
<property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tab_pos">bottom</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow2">
- <property name="hscrollbar_policy">never</property>
<property name="visible">True</property>
- <property name="vscrollbar_policy">automatic</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
<child>
<object class="GtkTextView" id="prettyprinttextview1">
- <property name="editable">False</property>
<property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
<property name="wrap_mode">word</property>
</object>
</child>
</object>
</child>
+ <child type="tab">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Pretty print</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow3">
- <property name="hscrollbar_policy">never</property>
<property name="visible">True</property>
- <property name="vscrollbar_policy">automatic</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
<child>
<object class="GtkTextView" id="sourcetextview1">
- <property name="editable">False</property>
<property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
<property name="wrap_mode">word</property>
</object>
</child>
</object>
<packing>
<property name="position">1</property>
- <property name="tab_label" context="yes" translatable="yes">Page 2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Source</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
- <property name="position">2</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
</packing>
</child>
- </object>
- <packing>
- <property name="position">2</property>
- </packing>
- </child>
- <child internal-child="action_area">
- <object class="GtkHButtonBox" id="dialog1-action_area">
- <property name="border_width">5</property>
- <property name="layout_style">end</property>
- <property name="spacing">6</property>
- <property name="visible">True</property>
<child>
- <object class="GtkButton" id="closebutton1">
- <property name="label" context="yes" translatable="yes">gtk-close</property>
- <property name="use_stock">True</property>
+ <object class="GtkBox" id="box2">
<property name="visible">True</property>
- <signal handler="execute_dialog_close_cb" name="clicked"/>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="yalign">0.49000000953674316</property>
+ <property name="xpad">1</property>
+ <property name="label" translatable="yes">&lt;b&gt;Method execution&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="method_exec_count_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_markup" translatable="yes">Number of method executions</property>
+ <property name="tooltip_text" translatable="yes">Number of method executions</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="climb_rate">1</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
</child>
<child>
- <object class="GtkButton" id="executebutton1">
- <property name="is_focus">True</property>
- <property name="use_underline">True</property>
- <property name="label" context="yes" translatable="yes">_Execute</property>
+ <object class="GtkBox" id="box_output_stats">
<property name="visible">True</property>
- <signal handler="execute_dbus_method_cb" name="clicked"/>
+ <property name="can_focus">False</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Ø:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_avg">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_markup" translatable="yes">Average method execution time in seconds</property>
+ <property name="tooltip_text" translatable="yes">Average method execution time in seconds</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Min:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_min">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_markup" translatable="yes">Minimal method execution time in seconds</property>
+ <property name="tooltip_text" translatable="yes">Minimal method execution time in seconds</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Max:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_max">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_markup" translatable="yes">Maximal method execution time in seconds</property>
+ <property name="tooltip_text" translatable="yes">Maximal method execution time in seconds</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
</object>
<packing>
- <property name="position">1</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">6</property>
</packing>
</child>
- </object>
+ </object>
<packing>
- <property name="expand">False</property>
- <property name="pack_type">end</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
</packing>
</child>
</object>
</child>
+ <action-widgets>
+ <action-widget response="0">closebutton1</action-widget>
+ <action-widget response="0">executebutton1</action-widget>
+ </action-widgets>
</object>
</interface>
diff --git a/ui/introspection.ui b/ui/introspection.ui
new file mode 100644
index 0000000..4185fcd
--- /dev/null
+++ b/ui/introspection.ui
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkBox" id="box_introspectview">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">&lt;b&gt;Unique name:&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">&lt;b&gt;Name:&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_unique_name">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_name">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">&lt;b&gt;Address:&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_address">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_reload">
+ <property name="label">gtk-refresh</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ <signal name="clicked" handler="on_button_reload_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">treestore</property>
+ <property name="search_column">0</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection1"/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkTreeStore" id="treestore">
+ <columns>
+ <!-- column-name gchararray1 -->
+ <column type="gchararray"/>
+ <!-- column-name GObject1 -->
+ <column type="GObject"/>
+ </columns>
+ </object>
+</interface>
diff --git a/ui/introspectview.ui b/ui/introspectview.ui
deleted file mode 100644
index 0f67c0d..0000000
--- a/ui/introspectview.ui
+++ /dev/null
@@ -1,118 +0,0 @@
-<?xml version="1.0"?>
-
-<interface>
- <object class="GtkTable" id="introspectview_table1">
- <property name="n_columns">2</property>
- <property name="n_rows">4</property>
- <property name="visible">True</property>
- <child>
- <object class="GtkLabel" id="label15">
- <property name="label" context="yes" translatable="yes">&lt;b&gt;Name: &lt;/b&gt;</property>
- <property name="use_markup">True</property>
- <property name="visible">True</property>
- <property name="xalign">1.0</property>
- <property name="yalign">0.0</property>
- </object>
- <packing>
- <property name="x_options">fill</property>
- <property name="y_options">fill | shrink</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label16">
- <property name="can_focus">True</property>
- <property name="label" context="yes" translatable="yes">&lt;b&gt;Unique Name: &lt;/b&gt;</property>
- <property name="selectable">True</property>
- <property name="use_markup">True</property>
- <property name="visible">True</property>
- <property name="xalign">1.0</property>
- <property name="yalign">0.0</property>
- </object>
- <packing>
- <property name="bottom_attach">2</property>
- <property name="top_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options">fill | shrink</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label17">
- <property name="label" context="yes" translatable="yes">&lt;b&gt;Command Line: &lt;/b&gt;</property>
- <property name="use_markup">True</property>
- <property name="visible">True</property>
- <property name="xalign">1.0</property>
- <property name="yalign">0.0</property>
- </object>
- <packing>
- <property name="bottom_attach">3</property>
- <property name="top_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options">fill | shrink</property>
- </packing>
- </child>
- <child>
- <object class="GtkVBox" id="introspect_box1">
- <property name="height_request">5</property>
- <property name="visible">True</property>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="bottom_attach">4</property>
- <property name="right_attach">2</property>
- <property name="top_attach">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="name_label1">
- <property name="can_focus">True</property>
- <property name="ellipsize">end</property>
- <property name="is_focus">True</property>
- <property name="selectable">True</property>
- <property name="visible">True</property>
- <property name="xalign">0.0</property>
- <property name="yalign">0.0</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="y_options">fill | shrink</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="unique_name_label1">
- <property name="can_focus">True</property>
- <property name="ellipsize">end</property>
- <property name="selectable">True</property>
- <property name="visible">True</property>
- <property name="xalign">0.0</property>
- </object>
- <packing>
- <property name="bottom_attach">2</property>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="y_options">fill | shrink</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="process_label1">
- <property name="can_focus">True</property>
- <property name="ellipsize">end</property>
- <property name="is_focus">True</property>
- <property name="selectable">True</property>
- <property name="visible">True</property>
- <property name="wrap">True</property>
- <property name="xalign">0.0</property>
- </object>
- <packing>
- <property name="bottom_attach">3</property>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">2</property>
- <property name="y_options">fill | shrink</property>
- </packing>
- </child>
- </object>
-</interface>
diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui
index c1093c2..fdef12d 100644
--- a/ui/mainwindow.ui
+++ b/ui/mainwindow.ui
@@ -1,45 +1,102 @@
-<?xml version="1.0" standalone="no"?>
-
+<?xml version="1.0" encoding="UTF-8"?>
<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkAction" id="action_close">
+ <property name="label" translatable="yes">Close</property>
+ <property name="stock_id">gtk-close</property>
+ <signal name="activate" handler="action_close_activate_cb" swapped="no"/>
+ </object>
+ <object class="GtkActionGroup" id="actiongroup_connect">
+ <child>
+ <object class="GtkAction" id="action_systembus_connect">
+ <property name="label" translatable="yes">Connect to System Bus</property>
+ <property name="short_label" translatable="yes">Connect to System Bus</property>
+ <property name="tooltip" translatable="yes">Connect to System Bus</property>
+ <property name="stock_id">gtk-connect</property>
+ <signal name="activate" handler="action_systembus_connect_activate_cb" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="action_sessionbus_connect">
+ <property name="label" translatable="yes">Connect to Session Bus</property>
+ <property name="short_label" translatable="yes">Connect to Session Bus</property>
+ <property name="tooltip" translatable="yes">Connect to Session Bus</property>
+ <property name="stock_id">gtk-connect</property>
+ <signal name="activate" handler="action_sessionbus_connect_activate_cb" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="action_otherbus_connect">
+ <property name="label" translatable="yes">Connect to other Bus</property>
+ <property name="short_label" translatable="yes">Connect to other Bus</property>
+ <property name="tooltip" translatable="yes">Connect to other Bus</property>
+ <property name="stock_id">gtk-connect</property>
+ <signal name="activate" handler="action_otherbus_connect_activate_cb" swapped="no"/>
+ </object>
+ </child>
+ </object>
<object class="GtkWindow" id="appwindow1">
- <property name="default_height">480</property>
- <property name="default_width">640</property>
- <property name="height_request">200</property>
- <property name="title" context="yes" translatable="yes">D-Feet D-Bus debugger</property>
- <property name="visible">False</property>
<property name="width_request">300</property>
+ <property name="height_request">200</property>
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes" context="yes">D-Feet D-Bus debugger</property>
+ <property name="default_width">640</property>
+ <property name="default_height">480</property>
+ <property name="icon_name">dfeet-icon</property>
<child>
- <object class="GtkVBox" id="main_vbox">
+ <object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
- <object class="GtkFrame" id="frame1">
- <property name="visible">True</property>
+ <object class="GtkMenuBar" id="menubar1">
+ <property name="can_focus">False</property>
<child>
- <object class="GtkVBox" id="vbox1">
+ <object class="GtkMenuItem" id="menuitem_file">
+ <property name="use_action_appearance">False</property>
<property name="visible">True</property>
- <child>
- <object class="GtkMenuBar" id="menubar1" constructor="default-uiman" />
- <packing>
- <property name="expand">False</property>
- </packing>
- </child>
- <child>
- <object constructor="default-uiman" class="GtkToolbar" id="toolbar1">
- <property name="toolbar_style">both-horiz</property>
- <property name="visible">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- </packing>
- </child>
- <child>
- <object class="GtkNotebook" id="display_notebook">
- <property name="enable_popup">True</property>
- <property name="is_focus">True</property>
- <property name="scrollable">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">File</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
- <placeholder/>
+ <object class="GtkMenuItem" id="menuitem_systembus">
+ <property name="related_action">action_systembus_connect</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem_sessionbus">
+ <property name="related_action">action_sessionbus_connect</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem_otherbus">
+ <property name="related_action">action_otherbus_connect</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menuitem1">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="menuitem_close">
+ <property name="related_action">action_close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
</child>
</object>
</child>
@@ -47,35 +104,77 @@
</child>
</object>
<packing>
- <property name="expand">True</property>
- </packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
</child>
<child>
- <object class="GtkFrame" id="frame2">
+ <object class="GtkToolbar" id="toolbar1">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<child>
- <object class="GtkNotebook" id="console_notebook">
- <property name="enable_popup">True</property>
- <property name="is_focus">True</property>
- <property name="scrollable">True</property>
+ <object class="GtkToolButton" id="toolbutton_systembus_connect">
+ <property name="related_action">action_systembus_connect</property>
<property name="visible">True</property>
- <child>
- <placeholder/>
- </child>
+ <property name="can_focus">False</property>
+ <property name="related_action">action_systembus_connect</property>
+ <property name="label" translatable="yes">toolbutton1</property>
+ <property name="use_underline">True</property>
</object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="toolbutton_sessionbus_connect">
+ <property name="related_action">action_sessionbus_connect</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="related_action">action_sessionbus_connect</property>
+ <property name="label" translatable="yes">toolbutton1</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="toolbutton_otherbus_connect">
+ <property name="related_action">action_otherbus_connect</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="related_action">action_otherbus_connect</property>
+ <property name="label" translatable="yes">toolbutton1</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
</child>
</object>
<packing>
<property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
</packing>
</child>
<child>
- <object class="GtkStatusbar" id="statusbar1">
+ <object class="GtkNotebook" id="display_notebook">
<property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="scrollable">True</property>
+ <child>
+ <placeholder/>
+ </child>
</object>
<packing>
- <property name="expand">False</property>
- <property name="pack_type">end</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
</packing>
</child>
</object>