2 #from logging import warn Not in Python2.2
7 _message_prop
= g
.gdk
.atom_intern('_XXMLRPC_MESSAGE', False)
8 _message_id_prop
= g
.gdk
.atom_intern('_XXMLRPC_ID', False)
10 class NoSuchService(Exception):
14 def __init__(self
, service
):
15 self
.service
= service
16 self
.objects
= {} # Path -> Object
18 # Can be used whether sending or receiving...
19 self
.ipc_window
= g
.Invisible()
20 self
.ipc_window
.add_events(g
.gdk
.PROPERTY_NOTIFY
)
22 self
.ipc_window
.realize()
24 # Append our window to the list for this service
26 # Make the IPC window contain a property pointing to
27 # itself - this can then be used to check that it really
30 self
.ipc_window
.window
.property_change(self
.service
,
32 g
.gdk
.PROP_MODE_REPLACE
,
33 [self
.ipc_window
.window
.xid
])
35 self
.ipc_window
.connect('property-notify-event',
36 self
.property_changed
)
38 # Make the root window contain a pointer to the IPC window
39 g
.gdk
.get_default_root_window().property_change(
40 self
.service
, 'XA_WINDOW', 32,
41 g
.gdk
.PROP_MODE_REPLACE
,
42 [self
.ipc_window
.window
.xid
])
44 def add_object(self
, path
, obj
):
45 if path
in self
.objects
:
46 raise Exception("An object with the path '%s' is already registered!" % path
)
47 assert isinstance(path
, str)
48 self
.objects
[path
] = obj
50 def remove_object(self
, path
):
51 del self
.objects
[path
]
53 def property_changed(self
, win
, event
):
54 if event
.atom
!= _message_id_prop
:
57 if event
.state
== g
.gdk
.PROPERTY_NEW_VALUE
:
58 val
= self
.ipc_window
.window
.property_get(
59 _message_id_prop
, 'XA_WINDOW', True)
61 self
.process_requests(val
[2])
63 def process_requests(self
, requests
):
65 foreign
= g
.gdk
.window_foreign_new(long(xid
))
66 xml
= foreign
.property_get(
67 _message_prop
, 'XA_STRING', False)
69 params
, method
= xmlrpclib
.loads(xml
[2])
70 retval
= self
.invoke(method
, *params
)
71 retxml
= xmlrpclib
.dumps(retval
, methodresponse
= True)
72 foreign
.property_change(_message_prop
, 'XA_STRING', 8,
73 g
.gdk
.PROP_MODE_REPLACE
, retxml
)
75 print >>sys
.stderr
, "No '%s' property on window %x" % (
78 def invoke(self
, method
, *params
):
80 raise Exception('No object path in message')
83 obj
= self
.objects
[obpath
]
85 return xmlrpclib
.Fault("UnknownObject",
86 "Unknown object '%s'" % obpath
)
87 if method
not in obj
.allowed_methods
:
88 return xmlrpclib
.Fault('NoSuchMethod',
89 "Method '%s' not a public method (check 'allowed_methods')" % method
)
91 method
= getattr(obj
, method
)
92 retval
= method(*params
[1:])
94 # XML-RPC doesn't allow returning None
100 #traceback.print_exc(file = sys.stderr)
101 return xmlrpclib
.Fault(ex
.__class
__.__name
__,
105 def __init__(self
, service
):
106 self
.service
= service
107 xid
= g
.gdk
.get_default_root_window().property_get(
108 self
.service
, 'XA_WINDOW', False)
111 raise NoSuchService("No such service '%s'" % service
)
112 # Note: xid[0] might be str or Atom
113 if str(xid
[0]) != 'XA_WINDOW' or \
116 raise Exception("Root property '%s' not a service!" % service
)
118 self
.remote
= g
.gdk
.window_foreign_new(long(xid
[2][0]))
119 if self
.remote
is None:
120 raise NoSuchService("Service '%s' is no longer running" % service
)
122 def get_object(self
, path
):
123 return XXMLObjectProxy(self
, path
)
125 class XXMLObjectProxy
:
126 def __init__(self
, service
, path
):
127 self
.service
= service
130 def __getattr__(self
, method
):
131 if method
.startswith('_'):
132 raise AttributeError("No attribute '" + method
+ "'")
134 call
= ClientCall(self
.service
, method
, tuple([self
.path
] + list(params
)))
138 class ClientCall(g
.Invisible
):
141 def __init__(self
, service
, method
, params
):
142 g
.Invisible
.__init
__(self
)
143 self
.service
= service
144 self
.add_events(g
.gdk
.PROPERTY_NOTIFY
)
147 self
.connect('property-notify-event',
148 self
.property_changed
)
150 # Store the message on our window
151 self
.ignore_next_change
= True
152 xml
= xmlrpclib
.dumps(params
, method
)
154 self
.window
.property_change(_message_prop
,
156 g
.gdk
.PROP_MODE_REPLACE
,
161 # Tell the service about it
162 self
.service
.remote
.property_change(_message_id_prop
,
164 g
.gdk
.PROP_MODE_APPEND
,
167 def property_changed(self
, win
, event
):
168 if event
.atom
!= _message_prop
:
171 if event
.state
== g
.gdk
.PROPERTY_NEW_VALUE
:
172 if self
.ignore_next_change
:
173 # This is just us sending the request
174 self
.ignore_next_change
= False
177 val
= self
.window
.property_get(
178 _message_prop
, 'XA_STRING', True)
180 raise Exception('No response to XML-RPC call')
182 self
.response
= val
[2]
186 def get_response(self
):
187 if self
.response
is None:
193 assert self
.response
is not None
194 retval
, method
= xmlrpclib
.loads(self
.response
)
195 assert len(retval
) == 1