WIP.
[ibus.git] / daemon / bus.py
blob5fc27bc83594a2ecf1ab2d0c7b7e2910ed979e14
1 # vim:set noet ts=4:
3 # ibus - The Input Bus
5 # Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this program; if not, write to the
19 # Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 # Boston, MA 02111-1307 USA
22 import weakref
23 import dbus
24 import ibus
25 from ibus import keysyms
26 from ibus import modifier
27 from contextmanager import ContextManager
28 from factorymanager import FactoryManager
29 from connection import Connection
30 from panel import Panel, DummyPanel
32 class IBus (ibus.Object):
33 def __init__ (self):
34 ibus.Object.__init__ (self)
35 self._connections = {}
36 self._context_manager = ContextManager ()
37 self._factory_manager = FactoryManager ()
38 self._panel = DummyPanel ()
40 self._focused_context = None
41 self._last_focused_context = None
42 self._context_handlers = []
44 self._last_key = None
46 def new_connection (self, dbusconn):
47 assert dbusconn not in self._connections
48 self._connections[dbusconn] = Connection (dbusconn)
50 def remove_connection (self, dbusconn):
51 assert dbusconn in self._connections
53 # destroy the connection
54 self._connections[dbusconn].destroy ()
55 del self._connections[dbusconn]
57 def _lookup_ibus_connection (self, dbusconn):
58 if dbusconn not in self._connections:
59 raise ibus.IBusException ("can not find ibus.Connection")
60 return self._connections[dbusconn]
62 ##########################################################
63 # methods for im context
64 ##########################################################
65 def create_input_context (self, name, dbusconn):
66 ibusconn = self._lookup_ibus_connection (dbusconn)
67 context = self._context_manager.create_input_context (name, ibusconn)
68 factory = self._factory_manager.get_default_factory ()
69 if factory:
70 engine = factory.create_engine ()
71 context.set_engine (engine)
72 return context.get_id ()
74 def release_input_context (self, ic, dbusconn):
75 ibusconn = self._lookup_ibus_connection (dbusconn)
76 self._context_manager.release_input_context (ic, ibusconn)
78 def focus_in (self, ic, dbusconn):
79 context = self._lookup_context (ic, dbusconn)
81 if self._focused_context != context and self._focused_context != None:
82 self._remove_focused_context_handlers ()
83 self._focused_context.focus_out ()
85 self._focused_context = context
86 self._install_focused_context_handlers ()
88 self._panel.focus_in (context.get_id ())
89 self._last_focused_context = context
90 context.focus_in ()
92 def focus_out (self, ic, dbusconn):
93 context = self._lookup_context (ic, dbusconn)
95 if context == self._focused_context:
96 self._remove_focused_context_handlers ()
97 self._focused_context = None
99 context.focus_out ()
100 self._panel.focus_out (context.get_id ())
102 def reset (self, ic, dbusconn):
103 context = self._lookup_context (ic, dbusconn)
104 context.reset ()
106 def is_enabled (self, ic, dbusconn):
107 context = self._lookup_context (ic, dbusconn)
108 return context.is_enabled ()
110 def process_key_event (self, ic, keyval, is_press, state,
111 dbusconn, reply_cb, error_cb):
112 context = self._lookup_context (ic, dbusconn)
114 if self._filter_hotkeys (context, keyval, is_press, state):
115 reply_cb (True)
116 return
117 else:
118 context.process_key_event (keyval, is_press, state, reply_cb, error_cb)
120 def set_cursor_location (self, ic, x, y, w, h, dbusconn):
121 context = self._lookup_context (ic, dbusconn)
122 context.set_cursor_location (x, y, w, h)
123 self._panel.set_cursor_location (x, y, w, h)
125 def _filter_hotkeys (self, context, keyval, is_press, state):
126 if is_press and keyval == keysyms.space \
127 and (state & ~modifier.MOD2_MASK) == modifier.CONTROL_MASK:
128 enable = not context.is_enabled ()
129 context.set_enable (enable)
130 if context.get_engine () == None and enable:
131 factory = self._factory_manager.get_default_factory ()
132 if factory:
133 engine = factory.create_engine ()
134 context.set_engine (engine)
135 self._panel.states_changed ()
136 return True
137 return False
139 def _lookup_context (self, ic, dbusconn):
140 ibusconn = self._lookup_ibus_connection (dbusconn)
141 return self._context_manager.lookup_context (ic, ibusconn)
143 def _install_focused_context_handlers (self):
144 # Install all callback functions
145 if self._focused_context == None:
146 return
147 signals = (
148 ("update-preedit", self._update_preedit_cb),
149 ("update-aux-string", self._update_aux_string_cb),
150 ("update-lookup-table", self._update_lookup_table_cb),
151 ("register-properties", self._register_properties_cb),
152 ("update-property", self._update_property_cb),
153 ("engine-lost", self._engine_lost_cb),
154 ("destroy", self._context_destroy_cb)
156 for name, handler in signals:
157 id = self._focused_context.connect (name, handler)
158 self._context_handlers.append (id)
160 def _remove_focused_context_handlers (self):
161 if self._focused_context == None:
162 return
163 map (self._focused_context.disconnect, self._context_handlers)
164 self._context_handlers = []
166 def _update_preedit_cb (self, context, text, attrs, cursor_pos, visible):
167 assert self._focused_context == context
169 self._panel.update_preedit_string (text, attrs, cursor_pos, visible)
171 def _update_aux_string_cb (self, context, text, attrs, visible):
172 assert self._focused_context == context
174 self._panel.update_aux_string (text, attrs, visible)
176 def _update_lookup_table_cb (self, context, lookup_table, visible):
177 assert self._focused_context == context
179 self._panel.update_lookup_table (lookup_table, visible)
181 def _register_properties_cb (self, context, props):
182 assert self._focused_context == context
184 self._panel.register_properties (props)
187 def _update_property_cb (self, context, prop):
188 assert self._focused_context == context
190 self._panel.update_property (prop)
192 def _engine_lost_cb (self, context):
193 assert self._focused_context == context
195 self._panel.reset ()
197 def _context_destroy_cb (self, context):
198 assert context == self._focused_context
199 self._remove_focused_context_handlers ()
200 self._focused_context = None
201 self._panel.reset ()
203 ##########################################################
204 # methods for im engines
205 ##########################################################
206 def register_factories (self, object_paths, dbusconn):
207 ibusconn = self._lookup_ibus_connection (dbusconn)
208 self._factory_manager.register_factories (object_paths, ibusconn)
210 def dispatch_dbus_signal (self, dbusconn, message):
211 ibusconn = self._lookup_ibus_connection (dbusconn)
212 ibusconn.dispatch_dbus_signal (message)
214 def _lookup_engine (self, dbusconn, path):
215 ibusconn = self._lookup_ibus_connection (dbusconn)
216 return self._factory_manager.lookup_engine (ibusconn, path)
219 ##########################################################
220 # methods for panel
221 ##########################################################
222 def register_panel (self, object_path, replace, dbusconn):
223 if not isinstance (self._panel, DummyPanel) and replace == False:
224 raise ibus.Exception ("has have a panel!")
225 if not isinstance (self._panel, DummyPanel):
226 self._panel.destroy ()
227 ibusconn = self._lookup_ibus_connection (dbusconn)
228 self._panel = Panel (ibusconn, object_path)
229 self._panel.connect ("page-up", self._panel_page_up_cb)
230 self._panel.connect ("page-down", self._panel_page_down_cb)
231 self._panel.connect ("cursor-up", self._panel_cursor_up_cb)
232 self._panel.connect ("cursor-down", self._panel_cursor_down_cb)
233 self._panel.connect ("property-activate", self._panel_property_active_cb)
234 self._panel.connect ("property-show", self._panel_property_show_cb)
235 self._panel.connect ("property-hide", self._panel_property_hide_cb)
236 self._panel.connect ("destroy", self._panel_destroy_cb)
238 def _panel_page_up_cb (self, panel):
239 assert panel == self._panel
240 if self._focused_context:
241 self._focused_context.page_up ()
243 def _panel_page_down_cb (self, panel):
244 assert panel == self._panel
245 if self._focused_context:
246 self._focused_context.page_down ()
248 def _panel_cursor_up_cb (self, panel):
249 assert panel == self._panel
250 if self._focused_context:
251 self._focused_context.cursor_up ()
253 def _panel_cursor_down_cb (self, panel):
254 assert panel == self._panel
255 if self._focused_context:
256 self._focused_context.cursor_down ()
258 def _panel_property_active_cb (self, panel, prop_name, prop_state):
259 assert panel == self._panel
260 if self._focused_context:
261 self._focused_context.property_activate (prop_name, prop_state)
263 def _panel_property_show_cb (self, panel, prop_name):
264 assert panel == self._panel
265 if self._focused_context:
266 self._focused_context.property_show (prop_name)
268 def _panel_property_hide_cb (self, panel, prop_name):
269 assert panel == self._panel
270 if self._focused_context:
271 self._focused_context.property_hide (prop_name)
273 def _panel_destroy_cb (self, panel):
274 if panel == self._panel:
275 self._panel = DummyPanel ()
277 ##########################################################
278 # general methods
279 ##########################################################
280 def get_factories (self):
281 return self._factory_manager.get_factories ()
283 def get_factory_info (self, factory_path):
284 return self._factory_manager.get_factory_info (factory_path)
286 def set_factory (self, factory_path):
287 if self._focused_context == None:
288 return
289 self._panel.reset ()
290 factory = self._factory_manager.get_factory (factory_path)
291 engine = factory.create_engine ()
292 self._focused_context.set_engine (engine)
294 def get_input_context_states (self, ic, dbusconn):
295 context = self._lookup_context (ic, dbusconn)
296 factory_path = "" if context.get_factory () == None else context.get_factory ().get_object_path ()
297 return factory_path, context.is_enabled ()
300 class IBusProxy (ibus.IIBus):
301 SUPPORTS_MULTIPLE_CONNECTIONS = True
303 def __init__ (self):
304 ibus.IIBus.__init__ (self)
305 self._ibus = IBus ()
307 def new_connection (self, dbusconn):
308 self._ibus.new_connection (dbusconn)
310 def remove_connection (self, dbusconn):
311 self._ibus.remove_connection (dbusconn)
313 def dispatch_dbus_signal (self, dbusconn, message):
314 return self._ibus.dispatch_dbus_signal (dbusconn, message)
316 def GetIBusAddress (self, dbusconn):
317 return self._ibus_addr
319 def CreateInputContext (self, context_name, dbusconn):
320 return self._ibus.create_input_context (context_name, dbusconn)
322 def ReleaseInputContext (self, ic, dbusconn):
323 self._ibus.release_input_context (ic, dbusconn)
325 def RegisterFactories (self, object_paths, dbusconn):
326 self._ibus.register_factories (object_paths, dbusconn)
328 def UnregisterEngines (self, object_paths, dbusconn):
329 self._ibus.unregister_engines (object_paths, dbusconn)
331 def RegisterPanel (self, object_path, replace, dbusconn):
332 self._ibus.register_panel (object_path, replace, dbusconn)
334 def ProcessKeyEvent (self, ic, keyval, is_press, state, \
335 dbusconn, reply_cb, error_cb):
336 try:
337 self._ibus.process_key_event (ic, keyval, is_press, state,
338 dbusconn, reply_cb, error_cb)
339 except Exception, e:
340 error_cb (e)
342 def SetCursorLocation (self, ic, x, y, w, h, dbusconn):
343 self._ibus.set_cursor_location (ic, x, y, w, h, dbusconn)
345 def FocusIn (self, ic, dbusconn):
346 self._ibus.focus_in (ic, dbusconn)
348 def FocusOut (self, ic, dbusconn):
349 self._ibus.focus_out (ic, dbusconn)
351 def Reset (self, ic, dbusconn):
352 self._ibus.reset (ic, dbusconn)
354 def IsEnabled (self, ic, dbusconn):
355 return self._ibus.is_enabled (ic, dbusconn)
357 def GetFactories (self, dbusconn):
358 return self._ibus.get_factories ()
360 def GetFactoryInfo (self, factory_path, dbusconn):
361 return self._ibus.get_factory_info (factory_path)
363 def SetFactory (self, factory_path, dbusconn):
364 return self._ibus.set_factory (factory_path)
366 def GetInputContextStates (self, ic, dbusconn):
367 return self._ibus.get_input_context_states (ic, dbusconn)