6
6
from dfeet.uiloader import UILoader
7
7
from dfeet.introspection import AddressInfo
8
from dfeet.wnck_utils import IconTable
11
class BusNameBox(Gtk.VBox):
12
"""class to represent a BusName (eg 'org.freedesktop.NetworkManager')"""
13
def __init__(self, bus_name, unique_name):
14
super(BusNameBox, self).__init__(spacing=5, expand=True)
15
self.__bus_name = bus_name
16
self.__unique_name = unique_name
18
self.__command_line = ''
19
self.__activatable = False
20
self.__icon_table = IconTable.get_instance()
21
self.__icon_image = Gtk.Image.new_from_pixbuf(self.__icon_table.default_icon)
23
self.__hbox = Gtk.HBox(spacing=5, halign=Gtk.Align.START)
24
self.pack_start(self.__hbox, True, True, 0)
26
self.__hbox.pack_start(self.__icon_image, True, True, 0)
28
self.__vbox_right = Gtk.VBox(spacing=5, expand=True)
29
self.__hbox.pack_start(self.__vbox_right, True, True, 0)
32
self.__label_bus_name = Gtk.Label()
33
self.__label_bus_name.set_halign(Gtk.Align.START)
34
self.__vbox_right.pack_start(self.__label_bus_name, True, True, 0)
36
self.__label_info = Gtk.Label()
37
self.__label_info.set_halign(Gtk.Align.START)
38
self.__vbox_right.pack_start(self.__label_info, True, True, 0)
39
#separator for the boxes
40
self.pack_end(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), True, True, 0)
41
#update widget information
42
self.__update_widget()
45
def __update_widget(self):
46
"""update the widget with the available information"""
47
if self.__process_id > 0:
48
self.__label_bus_name.set_markup("<b>{0}</b>".format(self.__bus_name))
50
self.__label_bus_name.set_markup("<b><i>{0}</i></b>".format(self.__bus_name))
51
#update the label info
52
label_info_str = "<small>"
53
if self.__activatable:
54
label_info_str += "activatable: yes"
56
label_info_str += "activatable: no"
58
label_info_str += ", pid: {0}".format(self.__process_id)
59
#get the icon (if available)
60
if self.__process_id in self.__icon_table.app_map.keys():
61
self.__icon_image.set_from_pixbuf(self.__icon_table.app_map[self.__process_id])
63
self.__icon_image.set_from_pixbuf(self.__icon_table.default_icon)
64
if self.__command_line:
65
label_info_str += ", cmd: {0}".format(self.__command_line)
66
label_info_str += "</small>"
67
self.__label_info.set_markup(label_info_str)
10
class DBusBusName(GObject.GObject):
11
"""class to represent a name on the bus"""
12
def __init__(self, bus_name_unique):
13
super(DBusBusName, self).__init__()
14
self.__bus_name_unique = bus_name_unique
69
18
def __repr__(self):
70
return "%s (pid: %s)" % (self.__bus_name, self.__process_id)
19
return "%s (pid: %s)" % (self.bus_name_unique, self.pid)
72
def __update_command_line(self):
73
"""get the command line of process-id is available"""
74
if self.__process_id > 0:
75
procpath = '/proc/' + str(self.__process_id) + '/cmdline'
21
def __update_cmdline(self):
23
procpath = '/proc/' + str(self.pid) + '/cmdline'
76
24
with open(procpath, 'r') as f:
77
self.__command_line = " ".join(f.readline().split('\0'))
25
self.__cmdline = " ".join(f.readline().split('\0'))
79
self.__command_line = ''
83
return self.__bus_name
86
def unique_name(self):
87
return self.__unique_name
90
def activatable(self):
91
return self.__activatable
94
def activatable(self, act_new):
95
self.__activatable = act_new
97
#update the shown widget
98
self.__update_widget()
101
def process_id(self):
102
return self.__process_id
105
def process_id(self, process_id_new):
106
self.__process_id = process_id_new
30
def bus_name_unique(self):
31
return self.__bus_name_unique
38
def pid(self, pid_new):
108
self.__update_command_line()
41
self.__update_cmdline()
110
self.__command_line = ''
111
#update the shown widget
112
self.__update_widget()
115
50
class BusWatch(object):
116
51
"""watch for a given bus"""
117
def __init__(self, data_dir, bus_address):
118
self.__data_dir = data_dir
119
self.__bus_address = bus_address
52
def __init__(self, data_dir, address):
53
self.data_dir = data_dir
54
self.address = address
121
ui = UILoader(self.__data_dir, UILoader.UI_BUS)
122
self.__box_bus = ui.get_root_widget()
123
self.__scrolledwindow_listbox = ui.get_widget("scrolledwindow_listbox")
124
self.__bus_name_filter = ui.get_widget('entry_filter')
125
#create a listbox for all the busnames
126
self.__listbox = Gtk.ListBox(hexpand=True, vexpand=True, expand=True)
127
self.__listbox.set_sort_func(self.__listbox_sort_by_name, None)
128
self.__listbox.set_filter_func(self.__listbox_filter_by_name, None)
129
self.__scrolledwindow_listbox.add(self.__listbox)
130
self.__scrolledwindow_listbox.show_all()
131
#setup the bus connection
132
if self.__bus_address == Gio.BusType.SYSTEM or self.__bus_address == Gio.BusType.SESSION:
134
self.connection = Gio.bus_get_sync(self.__bus_address, None)
135
elif Gio.dbus_is_supported_address(self.__bus_address):
56
ui = UILoader(self.data_dir, UILoader.UI_BUSWATCH)
57
self.paned_buswatch = ui.get_root_widget()
58
self.liststore_model = ui.get_widget('liststore_buswatch')
59
self.treemodelfilter_buswatch = ui.get_widget('treemodelfilter_buswatch')
60
self.treemodelfilter_buswatch.set_visible_func(self.__treemodelfilter_buswatch_cb)
61
self.treemodelsort_buswatch = ui.get_widget("treemodelsort_buswatch")
62
self.treemodelsort_buswatch.set_sort_func(2, self.__sort_on_name)
63
self.treemodelsort_buswatch.set_sort_column_id(2, Gtk.SortType.ASCENDING)
64
self.treeview = ui.get_widget('treeview_buswatch')
65
self.entry_filter = ui.get_widget('entry_filter')
66
self.grid_bus_name_selected_info = ui.get_widget('grid_bus_name_info')
67
self.label_bus_name_selected_name = ui.get_widget('label_bus_name_selected_name')
68
self.label_bus_name_selected_pid = ui.get_widget('label_bus_name_selected_pid')
69
self.label_bus_name_selected_cmdline = ui.get_widget('label_bus_name_selected_cmdline')
70
self.addr_info = None # hold the currently selected AddressInfo object
72
self.treeview.connect('cursor-changed',
73
self.__tree_view_cursor_changed_cb)
74
self.entry_filter.connect("changed",
75
self.__entry_filter_changed_cb)
78
if self.address == Gio.BusType.SYSTEM or self.address == Gio.BusType.SESSION:
79
self.connection = Gio.bus_get_sync(self.address, None)
80
elif Gio.dbus_is_supported_address(self.address):
137
81
self.connection = Gio.DBusConnection.new_for_address_sync(
139
83
Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT |
140
84
Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION,
143
raise ValueError("Invalid bus address '{0}'".format(self.__bus_address))
146
88
self.connection.signal_subscribe(None, "org.freedesktop.DBus", "NameOwnerChanged",
147
89
None, None, 0, self.__name_owner_changed_cb, None)
149
#refilter if someone wants to filter the busbox list
150
self.__bus_name_filter.connect("changed",
151
self.__bus_name_filter_changed_cb)
153
#change bus detail tree if a different bus is selected
154
self.__listbox.connect("row-selected",
155
self.__listbox_row_selected_cb)
158
91
self.bus_proxy = Gio.DBusProxy.new_sync(self.connection,
159
92
Gio.DBusProxyFlags.NONE,
162
95
'/org/freedesktop/DBus',
163
96
'org.freedesktop.DBus', None)
165
#get a list with activatable names
166
self.bus_proxy.ListActivatableNames('()',
167
result_handler=self.__list_act_names_handler,
168
error_handler=self.__list_act_names_error_handler)
171
99
self.bus_proxy.ListNames('()',
172
100
result_handler=self.__list_names_handler,
173
101
error_handler=self.__list_names_error_handler)
177
"""the main widget for the bus"""
178
return self.__box_bus
180
def __bus_name_filter_changed_cb(self, bus_name_filter):
181
"""someone typed something in the searchbox - refilter"""
182
self.__listbox.invalidate_filter()
184
def __listbox_row_selected_cb(self, listbox, listbox_row):
185
"""someone selected a different row of the listbox"""
186
childs = self.box_bus.get_children()
187
#never remove first element - that's the listbox with the busnames
189
self.box_bus.remove(childs[-1])
192
del(self.__addr_info)
196
#get the selected busname
198
row_childs = listbox_row.get_children()
199
bus_name_box = row_childs[0]
200
#add the introspection info to the left side
201
self.__addr_info = AddressInfo(self.__data_dir,
203
bus_name_box.bus_name,
204
bus_name_box.unique_name,
205
connection_is_bus=True)
206
self.box_bus.pack_end(self.__addr_info.introspect_box, True, True, 0)
207
self.box_bus.show_all()
103
def __treemodelfilter_buswatch_cb(self, model, iter, user_data):
104
#return model.get_value(iter, 1) in data
105
bus_name_obj = model.get(iter, 0)[0]
106
filter_text = self.entry_filter.get_text()
107
return filter_text.lower() in bus_name_obj.bus_name_unique.lower()
109
def __entry_filter_changed_cb(self, entry_filter):
110
self.treemodelfilter_buswatch.refilter()
112
def __tree_view_cursor_changed_cb(self, treeview):
113
"""do something when a row is selected"""
114
selection = self.treeview.get_selection()
116
model, iter_ = selection.get_selected()
120
bus_name_obj = model.get(iter_, 0)[0]
121
#remove current child
122
c2 = self.paned_buswatch.get_child2()
130
#add Introspection to paned
131
self.addr_info = AddressInfo(
132
self.data_dir, self.address, bus_name_obj.bus_name_unique, connection_is_bus=True)
133
self.paned_buswatch.add2(self.addr_info.introspect_box)
135
#update info about selected bus name
136
self.label_bus_name_selected_name.set_text(bus_name_obj.bus_name_unique)
137
self.label_bus_name_selected_pid.set_text("%s" % bus_name_obj.pid)
138
self.label_bus_name_selected_cmdline.set_text(bus_name_obj.cmdline)
139
self.grid_bus_name_selected_info.set_visible(True)
141
def __liststore_model_add(self, bus_name_obj):
142
"""add a DBusBusName object to the liststore model"""
143
#update bus info stuff
144
self.bus_proxy.GetConnectionUnixProcessID(
145
'(s)', bus_name_obj.bus_name_unique,
146
result_handler=self.__get_unix_process_id_cb,
147
error_handler=self.__get_unix_process_id_error_cb,
148
user_data=bus_name_obj)
149
#add bus to liststore
150
return self.liststore_model.append(
151
[bus_name_obj, 0, "%s" % (bus_name_obj.bus_name_unique), bus_name_obj.cmdline])
153
def __liststore_model_remove(self, bus_name_obj):
154
"""remove a DBusBusName object to the liststore model"""
155
for n, obj in enumerate(self.liststore_model):
156
if obj[2] == bus_name_obj.bus_name_unique:
157
del(self.liststore_model[n])
160
def __liststore_model_get(self, bus_name_obj):
161
"""get a object from the liststore"""
162
for n, obj in enumerate(self.liststore_model):
163
if obj[2] == bus_name_obj.bus_name_unique:
165
raise Exception("bus name object '%s' not found in liststore" % (bus_name_obj))
209
167
def __name_owner_changed_cb(self, connection, sender_name,
210
168
object_path, interface_name, signal_name,
214
172
old_owner = parameters[1]
215
173
new_owner = parameters[2]
175
bus_name_obj = DBusBusName(bus_name)
217
177
if bus_name[0] == ':':
218
178
if not old_owner:
219
bus_name_box = BusNameBox(bus_name, new_owner)
220
self.__listbox_add_bus_name(bus_name_box)
179
self.__liststore_model_add(bus_name_obj)
222
self.__listbox_remove_bus_name(bus_name)
181
self.__liststore_model_remove(bus_name_obj)
225
bus_name_box = BusNameBox(bus_name, new_owner)
226
self.__listbox_add_bus_name(bus_name_box)
184
self.__liststore_model_add(bus_name_obj)
228
self.__listbox_remove_bus_name(bus_name)
230
def __listbox_find_bus_name(self, bus_name):
231
"""find the given busname in the listbox or return None if not found"""
232
for listbox_child in self.__listbox.get_children():
233
if listbox_child.get_children()[0].bus_name == bus_name:
238
def __listbox_remove_bus_name(self, bus_name):
239
"""remove the given busname from the listbox"""
240
obj = self.__listbox_find_bus_name(bus_name)
242
self.__listbox.remove(obj)
243
#if bus is activatable, add the bus name again
244
if bus_name in self.__activatable_names:
245
bnb = BusNameBox(bus_name, '')
246
self.__listbox_add_bus_name(bnb)
248
print("can not remove busname '{0}'. busname not found".format(bus_name))
250
def __listbox_add_bus_name(self, bus_name_box):
251
"""add the given busnamebox to the listbox and update the info"""
252
#first check if busname is already listed
253
#ie an activatable (but inactive) busname
254
bn = self.__listbox_find_bus_name(bus_name_box.bus_name)
256
#bus name is already in the list - use this
257
bus_name_box = bn.get_children()[0]
259
#add busnamebox to the list
260
self.__listbox.add(bus_name_box)
262
#update bus info stuff
263
self.bus_proxy.GetConnectionUnixProcessID(
264
'(s)', bus_name_box.bus_name,
265
result_handler=self.__get_unix_process_id_cb,
266
error_handler=self.__get_unix_process_id_error_cb,
267
user_data=bus_name_box)
268
#check if bus name is dbus activatable
269
if bus_name_box.bus_name in self.__activatable_names:
270
bus_name_box.activatable = True
272
bus_name_box.activatable = False
274
def __add_name(self, name, unique_name):
275
bus_name_box = BusNameBox(name, unique_name)
276
self.__listbox_add_bus_name(bus_name_box)
278
def __get_name_owner_cb(self, obj, unique_name, name):
279
self.__add_name(name, unique_name)
281
def __get_name_owner_error_cb(self, obj, error, name):
282
# no name owner, empty unique name
283
self.__add_name(name, '')
285
def __add_names(self, names):
186
self.__liststore_model_remove(bus_name_obj)
188
def __list_names_handler(self, obj, names, userdata):
287
#unique names are added right away
289
self.__add_name(n, n)
291
self.bus_proxy.GetNameOwner('(s)', n,
292
result_handler=self.__get_name_owner_cb,
293
error_handler=self.__get_name_owner_error_cb,
296
def __list_names_handler(self, obj, names, userdata):
297
self.__add_names(names)
190
bus_name_obj = DBusBusName(n)
191
self.__liststore_model_add(bus_name_obj)
299
193
def __list_names_error_handler(self, obj, error, userdata):
300
194
print("error getting bus names: %s" % str(error))
302
def __list_act_names_handler(self, obj, act_names, userdata):
303
#remember the activatable bus names
304
self.__activatable_names = act_names
305
#add all activatable bus names to the list
306
self.__add_names(act_names)
308
def __list_act_names_error_handler(self, obj, error, userdata):
309
self.__activatable_names = []
310
print("error getting activatable names: %s" % str(error))
312
def __get_unix_process_id_cb(self, obj, pid, bus_name_box):
313
bus_name_box.process_id = pid
315
def __get_unix_process_id_error_cb(self, obj, error, bus_name_box):
316
#print("error getting unix process id for %s: %s" % (
317
# bus_name_box.bus_name, str(error)))
318
bus_name_box.process_id = 0
320
def __listbox_filter_by_name(self, row, user_data):
321
bus_name_box_list = row.get_children()
322
return self.__bus_name_filter.get_text().lower() in bus_name_box_list[0].bus_name.lower()
324
def __listbox_sort_by_name(self, row1, row2, user_data):
325
"""sort function for listbox"""
326
child1 = row1.get_children()
327
child2 = row2.get_children()
328
un1 = child1[0].bus_name
329
un2 = child2[0].bus_name
196
def __get_unix_process_id_cb(self, obj, pid, bus_name_obj):
197
bus_name_obj.pid = pid
199
def __get_unix_process_id_error_cb(self, obj, error, bus_name_obj):
201
"error getting unix process id for %s: %s" % (
202
bus_name_obj.bus_name_unique, str(error)))
205
def __sort_on_name(self, model, iter1, iter2, user_data):
206
un1 = model.get_value(iter1, 2)
207
un2 = model.get_value(iter2, 2)
331
209
# covert to integers if comparing two unique names
332
210
if un1[0] == ':' and un2[0] == ':':