5 import dbus
.mainloop
.glib
8 from calfgtkutils
import *
9 Colors
= conndiagram
.Colors
11 class JACKPortInfo(object):
17 def __init__(self
, full_name
, port_id
, name
, flags
, format
):
18 self
.full_name
= full_name
19 self
.client_name
= full_name
.split(":", 1)[0]
20 self
.port_id
= int(port_id
)
22 self
.flags
= int(flags
)
23 self
.format
= int(format
)
32 return self
.format
== 0
35 return self
.format
== 1
37 def is_port_input(self
):
38 return (self
.flags
& 1) != 0
40 def is_port_output(self
):
41 return (self
.flags
& 2) != 0
43 def get_port_color(self
):
45 return Colors
.audioPort
47 return Colors
.eventPort
49 print "Unknown type %s" % self
.format
50 return Colors
.controlPort
52 class JACKClientInfo(object):
55 def __init__(self
, id, name
, ports
):
63 def add_port(self
, port_id
, name
, flags
, format
):
64 model
= JACKPortInfo("%s:%s" % (self
.name
, name
), port_id
, name
, flags
, format
)
65 self
.ports
.append(model
)
68 class JACKGraphInfo(object):
70 def __init__(self
, version
, clients
, connections
):
71 self
.version
= version
74 self
.connections_id
= set()
75 self
.connections_name
= set()
78 for tuple in connections
:
79 self
.add_connection(*tuple)
81 def add_client(self
, id, name
, ports
):
82 c
= JACKClientInfo(id, name
, ports
)
83 self
.clients
.append(c
)
84 self
.client_map
[name
] = c
86 def add_connection(self
, cid1
, cname1
, pid1
, pname1
, cid2
, cname2
, pid2
, pname2
, something
):
87 self
.connections_name
.add(("%s:%s" % (cname1
, pname1
), "%s:%s" % (cname2
, pname2
)))
88 self
.connections_id
.add(("%s:%s" % (cid1
, pid1
), "%s:%s" % (cid2
, pid2
)))
90 class ClientModuleModel():
91 def __init__(self
, client
, checker
):
92 (self
.client
, self
.checker
) = (client
, checker
)
94 return self
.client
.get_name()
95 def get_port_list(self
):
96 return filter(self
.checker
, self
.client
.ports
)
98 class JACKGraphController(object):
100 dbus
.mainloop
.glib
.DBusGMainLoop(set_as_default
=True)
101 self
.bus
= dbus
.SessionBus()
102 self
.service
= self
.bus
.get_object("org.jackaudio.service", "/org/jackaudio/Controller")
103 self
.patchbay
= dbus
.Interface(self
.service
, "org.jackaudio.JackPatchbay")
107 self
.patchbay
.connect_to_signal('PortAppeared', self
.port_appeared
)
108 self
.patchbay
.connect_to_signal('PortDisappeared', self
.port_disappeared
)
109 self
.patchbay
.connect_to_signal('PortsConnected', self
.ports_connected
)
110 self
.patchbay
.connect_to_signal('PortsDisconnected', self
.ports_disconnected
)
111 def port_appeared(self
, seq_no
, client_id
, client_name
, port_id
, port_name
, flags
, format
):
112 model
= self
.graph
.client_map
[str(client_name
)].add_port(int(port_id
), str(port_name
), int(flags_format
))
113 print "PortAppeared", model
114 def port_disappeared(self
, seq_no
, client_id
, client_name
, port_id
, port_name
):
115 print "PortDisappeared", str(client_name
), str(port_name
)
116 def ports_connected(self
, *args
):
117 print "PortsConnected", args
118 self
.graph
.add_connection(*args
[1:])
119 def ports_disconnected(self
, *args
):
120 print "PortsDisconnected", args
121 def fetch_graph(self
):
122 req_version
= self
.graph
.version
if self
.graph
is not None else 0
123 graphdata
= self
.patchbay
.GetGraph(req_version
)
124 if int(graphdata
[0]) != req_version
:
125 self
.graph
= JACKGraphInfo(*graphdata
)
126 def can_connect(self
, first
, second
):
127 if first
.is_port_input() == second
.is_port_input():
129 if first
.is_audio() and second
.is_audio():
131 if first
.is_midi() and second
.is_midi():
134 def is_connected(self
, first
, second
):
135 return (first
.get_id(), second
.get_id()) in self
.graph
.connections_name
136 def connect(self
, first
, second
):
137 if self
.is_connected(first
, second
):
138 self
.disconnect(first
, second
)
140 self
.patchbay
.ConnectPortsByName(first
.client_name
, first
.name
, second
.client_name
, second
.name
)
141 self
.graph
.connections_name
.add((first
.get_id(), second
.get_id()))
142 self
.view
.connect(self
.view
.get_port_view(first
), self
.view
.get_port_view(second
))
143 def disconnect(self
, first
, second
):
144 self
.patchbay
.DisconnectPortsByName(first
.client_name
, first
.name
, second
.client_name
, second
.name
)
145 self
.graph
.connections_name
.remove((first
.get_id(), second
.get_id()))
146 self
.view
.disconnect(self
.view
.get_port_view(first
), self
.view
.get_port_view(second
))
152 width
, left_mods
= self
.add_clients(10.0, 10.0, lambda port
: port
.is_port_output())
153 width2
, right_mods
= self
.add_clients(width
+ 20, 10.0, lambda port
: port
.is_port_input())
154 pmap
= self
.view
.get_port_map()
155 for (c
, p
) in self
.graph
.connections_name
:
156 if p
in pmap
and c
in pmap
:
157 print "Connect %s to %s" % (c
, p
)
158 self
.view
.connect(pmap
[c
], pmap
[p
])
160 print "Connect %s to %s - not found" % (c
, p
)
162 m
.translate(width
- m
.width
, 0)
164 m
.translate(950 - width
- 30 - width2
, 0)
165 def add_clients(self
, x
, y
, checker
):
169 for cl
in self
.graph
.clients
:
170 mod
= self
.view
.add_module(ClientModuleModel(cl
, checker
), x
, y
)
171 y
+= mod
.rect
.props
.height
+ margin
172 if mod
.rect
.props
.width
> mwidth
:
173 mwidth
= mod
.rect
.props
.width
179 self
.controller
= JACKGraphController()
180 self
.cgraph
= conndiagram
.ConnectionGraphEditor(self
, self
.controller
)
181 self
.controller
.view
= self
.cgraph
183 def canvas_popup_menu_handler(self
, widget
):
184 self
.canvas_popup_menu(0, 0, 0)
187 def canvas_popup_menu(self
, x
, y
, time
):
189 items
= self
.cgraph
.get_data_items_at(x
, y
)
194 add_option(menu
, "Disconnect", self
.disconnect
, wire
)
199 add_option(menu
, "Disconnect All", self
.disconnect_all
, port
, enabled
= len(port
.get_connections()))
204 menu
.popup(None, None, None, 3, time
)
206 def disconnect(self
, wire
):
207 self
.controller
.disconnect(wire
.src
.model
, wire
.dest
.model
)
210 def disconnect_all(self
, port
):
211 for wire
in list(port
.module
.wires
):
212 if wire
.src
== port
or wire
.dest
== port
:
213 self
.controller
.disconnect(wire
.src
.model
, wire
.dest
.model
)
217 self
.window
= gtk
.Window(gtk
.WINDOW_TOPLEVEL
)
218 self
.window
.connect("delete_event", self
.delete_event
)
219 self
.window
.connect("destroy", self
.destroy
)
220 self
.main_vbox
= gtk
.VBox()
221 self
.create_main_menu()
222 self
.scroll
= gtk
.ScrolledWindow()
223 self
.scroll
.add(self
.cgraph
.create(950, 650))
224 self
.main_vbox
.pack_start(self
.menu_bar
, expand
= False, fill
= False)
225 self
.main_vbox
.add(self
.scroll
)
226 self
.window
.add(self
.main_vbox
)
227 self
.window
.show_all()
228 self
.main_vbox
.connect("popup-menu", self
.canvas_popup_menu_handler
)
229 self
.controller
.add_all()
231 self
.controller
.add_all()
232 self
.cgraph
.canvas
.update()
234 #self.cgraph.blow_up()
236 def create_main_menu(self
):
237 self
.menu_bar
= gtk
.MenuBar()
238 self
.file_menu
= add_submenu(self
.menu_bar
, "_File")
239 add_option(self
.file_menu
, "_Refresh", self
.refresh
)
240 add_option(self
.file_menu
, "_Blow-up", self
.blow_up
)
241 add_option(self
.file_menu
, "_Exit", self
.exit
)
243 def refresh(self
, data
):
244 self
.controller
.refresh()
246 def blow_up(self
, data
):
247 self
.cgraph
.blow_up()
249 def exit(self
, data
):
250 self
.window
.destroy()
252 def delete_event(self
, widget
, data
= None):
254 def destroy(self
, widget
, data
= None):