1 # vim:set et sts=4 sw=4:
5 # Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
6 # Copyright (c) 2007-2010 Red Hat, Inc.
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2 of the License, or (at your option) any later version.
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU Lesser General Public License for more details.
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this program; if not, write to the
20 # Free Software Foundation, Inc., 59 Temple Place, Suite 330,
21 # Boston, MA 02111-1307 USA
28 from gi.repository import GLib
29 from gi.repository import Gtk
30 from gi.repository import IBus
32 from xdg import BaseDirectory
34 import keyboardshortcut
36 from enginecombobox import EngineComboBox
37 from enginetreeview import EngineTreeView
38 from engineabout import EngineAbout
39 from i18n import DOMAINNAME, _, N_, init as i18n_init
63 def __flush_gtk_events(self):
64 while Gtk.events_pending():
68 super(Setup, self).__init__()
69 gtk_builder_file = path.join(path.dirname(__file__), "./setup.ui")
70 self.__builder = Gtk.Builder()
71 self.__builder.set_translation_domain(DOMAINNAME)
72 self.__builder.add_from_file(gtk_builder_file);
77 def __init_hotkey(self):
79 "trigger" : (N_("trigger"), ["Control+space"]),
80 "enable_unconditional" : (N_("enable"), []),
81 "disable_unconditional" : (N_("disable"), [])
84 values = dict(self.__config.get_values("general/hotkey"))
86 for name, (label, shortcuts) in default_values.items():
87 shortcuts = values.get(name, shortcuts)
88 button = self.__builder.get_object("button_%s" % name)
89 entry = self.__builder.get_object("entry_%s" % name)
90 entry.set_text("; ".join(shortcuts))
91 entry.set_tooltip_text("\n".join(shortcuts))
92 button.connect("clicked", self.__shortcut_button_clicked_cb,
93 label, "general/hotkey", name, entry)
95 def __init_panel(self):
96 values = dict(self.__config.get_values("panel"))
98 # lookup table orientation
99 self.__combobox_lookup_table_orientation = self.__builder.get_object(
100 "combobox_lookup_table_orientation")
101 self.__combobox_lookup_table_orientation.set_active(
102 values.get("lookup_table_orientation", 0))
103 self.__combobox_lookup_table_orientation.connect("changed",
104 self.__combobox_lookup_table_orientation_changed_cb)
107 self.__combobox_panel_show = self.__builder.get_object(
108 "combobox_panel_show")
109 self.__combobox_panel_show.set_active(values.get("show", 0))
110 self.__combobox_panel_show.connect("changed",
111 self.__combobox_panel_show_changed_cb)
114 self.__combobox_panel_position = self.__builder.get_object(
115 "combobox_panel_position")
116 self.__combobox_panel_position.set_active(values.get("position", 3))
117 self.__combobox_panel_position.connect("changed",
118 self.__combobox_panel_position_changed_cb)
121 self.__checkbutton_custom_font = self.__builder.get_object(
122 "checkbutton_custom_font")
123 self.__checkbutton_custom_font.set_active(
124 values.get("use_custom_font", False))
125 self.__checkbutton_custom_font.connect("toggled",
126 self.__checkbutton_custom_font_toggled_cb)
128 self.__fontbutton_custom_font = self.__builder.get_object(
129 "fontbutton_custom_font")
130 if values.get("use_custom_font", False):
131 self.__fontbutton_custom_font.set_sensitive(True)
133 self.__fontbutton_custom_font.set_sensitive(False)
134 font_name = Gtk.Settings.get_default().get_property("gtk-font-name")
135 font_name = unicode(font_name, "utf-8")
136 font_name = values.get("custom_font", font_name)
137 self.__fontbutton_custom_font.connect("notify::font-name",
138 self.__fontbutton_custom_font_notify_cb)
139 self.__fontbutton_custom_font.set_font_name(font_name)
141 # show icon on system tray
142 self.__checkbutton_show_icon_on_systray = self.__builder.get_object(
143 "checkbutton_show_icon_on_systray")
144 self.__checkbutton_show_icon_on_systray.set_active(
145 values.get("show_icon_on_systray", True))
146 self.__checkbutton_show_icon_on_systray.connect("toggled",
147 self.__checkbutton_show_icon_on_systray_toggled_cb)
150 self.__checkbutton_show_im_name = self.__builder.get_object(
151 "checkbutton_show_im_name")
152 self.__checkbutton_show_im_name.set_active(
153 values.get("show_im_name", False))
154 self.__checkbutton_show_im_name.connect("toggled",
155 self.__checkbutton_show_im_name_toggled_cb)
157 def __init_general(self):
158 values = dict(self.__config.get_values("general"))
161 self.__checkbutton_embed_preedit_text = self.__builder.get_object(
162 "checkbutton_embed_preedit_text")
163 self.__checkbutton_embed_preedit_text.set_active(
164 values.get("embed_preedit_text", True))
165 self.__checkbutton_embed_preedit_text.connect("toggled",
166 self.__checkbutton_embed_preedit_text_toggled_cb)
168 # use system keyboard layout setting
169 self.__checkbutton_use_sys_layout = self.__builder.get_object(
170 "checkbutton_use_sys_layout")
171 self.__checkbutton_use_sys_layout.set_active(
172 values.get("use_system_keyboard_layout", True))
173 self.__checkbutton_use_sys_layout.connect("toggled",
174 self.__checkbutton_use_sys_layout_toggled_cb)
176 # use global ime setting
177 self.__checkbutton_use_global_engine = self.__builder.get_object(
178 "checkbutton_use_global_engine")
179 self.__checkbutton_use_global_engine.set_active(
180 values.get("use_global_engine", False))
181 self.__checkbutton_use_global_engine.connect("toggled",
182 self.__checkbutton_use_global_engine_toggled_cb)
185 self.__engines = self.__bus.list_engines()
186 self.__combobox = self.__builder.get_object("combobox_engines")
187 self.__combobox.set_engines(self.__engines)
190 for e in self.__engines:
191 tmp_dict[e.get_name()] = e
192 engine_names = values.get("preload_engines", [])
193 engines = [tmp_dict[name] for name in engine_names if name in tmp_dict]
195 self.__treeview = self.__builder.get_object("treeview_engines")
196 self.__treeview.set_engines(engines)
198 button = self.__builder.get_object("button_engine_add")
199 button.connect("clicked", self.__button_engine_add_cb)
200 button = self.__builder.get_object("button_engine_remove")
201 button.connect("clicked", lambda *args:self.__treeview.remove_engine())
202 button = self.__builder.get_object("button_engine_up")
203 button.connect("clicked", lambda *args:self.__treeview.move_up_engine())
205 button = self.__builder.get_object("button_engine_down")
206 button.connect("clicked",
207 lambda *args:self.__treeview.move_down_engine())
209 button = self.__builder.get_object("button_engine_about")
210 button.connect("clicked", self.__button_engine_about_cb)
212 self.__engine_setup_exec_list = {}
213 button = self.__builder.get_object("button_engine_preferences")
214 button.connect("clicked", self.__button_engine_preferences_cb)
216 self.__combobox.connect("notify::active-engine",
217 self.__combobox_notify_active_engine_cb)
218 self.__treeview.connect("notify::active-engine", self.__treeview_notify_cb)
219 self.__treeview.connect("notify::engines", self.__treeview_notify_cb)
222 # add icon search path
223 self.__window = self.__builder.get_object("window_preferences")
224 self.__window.connect("delete-event", Gtk.main_quit)
226 self.__button_close = self.__builder.get_object("button_close")
227 self.__button_close.connect("clicked", Gtk.main_quit)
230 self.__checkbutton_auto_start = self.__builder.get_object(
231 "checkbutton_auto_start")
232 self.__checkbutton_auto_start.set_active(self.__is_auto_start())
233 self.__checkbutton_auto_start.connect("toggled",
234 self.__checkbutton_auto_start_toggled_cb)
236 self.__config = self.__bus.get_config()
240 self.__init_general()
242 def __combobox_notify_active_engine_cb(self, combobox, property):
243 engine = self.__combobox.get_active_engine()
244 button = self.__builder.get_object("button_engine_add")
245 button.set_sensitive(
246 engine != None and engine not in self.__treeview.get_engines())
248 def __get_engine_setup_exec_args(self, engine):
252 setup = str(engine.get_setup())
255 args.insert(1, path.basename(args[0]))
257 name = str(engine.get_name())
258 libexecdir = os.environ['IBUS_LIBEXECDIR']
259 setup_path = (libexecdir + '/' + 'ibus-setup-' if libexecdir != None \
260 else 'ibus-setup-') + name.split(':')[0]
261 if path.exists(setup_path):
262 args.append(setup_path)
263 args.append(path.basename(setup_path))
266 def __treeview_notify_cb(self, treeview, prop):
267 if prop.name not in ("active-engine", "engines"):
270 engines = self.__treeview.get_engines()
271 engine = self.__treeview.get_active_engine()
273 self.__builder.get_object("button_engine_remove").set_sensitive(engine != None)
274 self.__builder.get_object("button_engine_about").set_sensitive(engine != None)
275 self.__builder.get_object("button_engine_up").set_sensitive(engine not in engines[:1])
276 self.__builder.get_object("button_engine_down").set_sensitive(engine not in engines[-1:])
278 obj = self.__builder.get_object("button_engine_preferences")
279 if len(self.__get_engine_setup_exec_args(engine)) != 0:
280 obj.set_sensitive(True)
282 obj.set_sensitive(False)
284 if prop.name == "engines":
285 engine_names = map(lambda e: e.get_name(), engines)
286 value = GLib.Variant.new_strv(engine_names)
287 self.__config.set_value("general", "preload_engines", value)
289 def __button_engine_add_cb(self, button):
290 engine = self.__combobox.get_active_engine()
291 self.__treeview.append_engine(engine)
293 def __button_engine_about_cb(self, button):
294 engine = self.__treeview.get_active_engine()
296 about = EngineAbout(engine)
300 def __button_engine_preferences_cb(self, button):
301 engine = self.__treeview.get_active_engine()
302 args = self.__get_engine_setup_exec_args(engine)
305 name = engine.get_name()
306 if name in self.__engine_setup_exec_list.keys():
308 wpid, sts = os.waitpid(self.__engine_setup_exec_list[name],
310 # the setup is still running.
315 del self.__engine_setup_exec_list[name]
316 self.__engine_setup_exec_list[name] = os.spawnl(os.P_NOWAIT, *args)
318 def __init_bus(self):
319 self.__bus = IBus.Bus()
320 if self.__bus.is_connected():
323 message = _("IBus daemon is not started. Do you want to start it now?")
324 dlg = Gtk.MessageDialog(type = Gtk.MessageType.QUESTION,
325 buttons = Gtk.ButtonsType.YES_NO,
329 self.__flush_gtk_events()
330 if id != Gtk.ResponseType.YES:
333 main_loop = GLib.MainLoop()
336 GLib.timeout_add_seconds(timeout, lambda *args: main_loop.quit())
337 self.__bus.connect("connected", lambda *args: main_loop.quit())
339 os.spawnlp(os.P_NOWAIT, "ibus-daemon", "ibus-daemon", "--xim")
343 if self.__bus.is_connected():
344 message = _("IBus has been started! "
345 "If you can not use IBus, please add below lines in $HOME/.bashrc, and relogin your desktop.\n"
346 " export GTK_IM_MODULE=ibus\n"
347 " export XMODIFIERS=@im=ibus\n"
348 " export QT_IM_MODULE=ibus"
350 dlg = Gtk.MessageDialog(type = Gtk.MessageType.INFO,
351 buttons = Gtk.ButtonsType.OK,
355 self.__flush_gtk_events()
357 message = _("IBus daemon coundn't be started in %d seconds")
358 dlg = Gtk.MessageDialog(type = Gtk.MessageType.INFO,
359 buttons = Gtk.ButtonsType.OK,
360 text = message % timeout)
363 self.__flush_gtk_events()
366 def __shortcut_button_clicked_cb(self, button, name, section, _name, entry):
367 buttons = (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
368 Gtk.STOCK_OK, Gtk.ResponseType.OK)
369 title = _("Select keyboard shortcut for %s") % _(name)
370 dialog = keyboardshortcut.KeyboardShortcutSelectionDialog(buttons = buttons, title = title)
371 text = entry.get_text()
373 shortcuts = text.split("; ")
376 dialog.set_shortcuts(shortcuts)
378 shortcuts = dialog.get_shortcuts()
380 if id != Gtk.ResponseType.OK:
382 self.__config.set_value(section, _name, GLib.Variant.new_strv(shortcuts))
383 text = "; ".join(shortcuts)
385 entry.set_tooltip_text(text)
388 def __item_started_column_toggled_cb(self, cell, path_str, model):
391 iter = model.get_iter_from_string(path_str)
392 data = model.get_value(iter, COLUMN_DATA)
394 # do something with the value
395 if data[DATA_STARTED] == False:
397 self.__bus.register_start_engine(data[DATA_LANG], data[DATA_NAME])
399 dlg = Gtk.MessageDialog(type = Gtk.MessageType.ERROR,
400 buttons = Gtk.ButtonsType.CLOSE,
401 message_format = str(e))
404 self.__flush_gtk_events()
408 self.__bus.register_stop_engine(data[DATA_LANG], data[DATA_NAME])
410 dlg = Gtk.MessageDialog(type = Gtk.MessageType.ERROR,
411 buttons = Gtk.ButtonsType.CLOSE,
412 message_format = str(e))
415 self.__flush_gtk_events()
417 data[DATA_STARTED] = not data[DATA_STARTED]
420 model.set(iter, COLUMN_ENABLE, data[DATA_STARTED])
422 def __item_preload_column_toggled_cb(self, cell, path_str, model):
425 iter = model.get_iter_from_string(path_str)
426 data = model.get_value(iter, COLUMN_DATA)
428 data[DATA_PRELOAD] = not data[DATA_PRELOAD]
429 engine = "%s:%s" % (data[DATA_LANG], data[DATA_NAME])
431 if data[DATA_PRELOAD]:
432 if engine not in self.__preload_engines:
433 self.__preload_engines.add(engine)
434 value = GLib.Variant.new_strv(list(self.__preload_engines))
435 self.__config.set_value("general", "preload_engines", value)
437 if engine in self.__preload_engines:
438 self.__preload_engines.remove(engine)
439 value = GLib.Variant.new_strv(list(self.__preload_engines))
440 self.__config.set_value("general", "preload_engines", value)
443 model.set(iter, COLUMN_PRELOAD, data[DATA_PRELOAD])
445 def __is_auto_start(self):
446 link_file = path.join(BaseDirectory.xdg_config_home, "autostart/IBus.desktop")
447 ibus_desktop = path.join(os.getenv("IBUS_PREFIX"), "share/applications/IBus.desktop")
449 if not path.exists(link_file):
451 if not path.islink(link_file):
453 if path.realpath(link_file) != ibus_desktop:
457 def __checkbutton_auto_start_toggled_cb(self, button):
458 auto_start_dir = path.join(BaseDirectory.xdg_config_home, "autostart")
459 if not path.isdir(auto_start_dir):
460 os.makedirs(auto_start_dir)
462 link_file = path.join(BaseDirectory.xdg_config_home, "autostart/IBus.desktop")
463 ibus_desktop = path.join(os.getenv("IBUS_PREFIX"), "share/applications/IBus.desktop")
469 if self.__checkbutton_auto_start.get_active():
470 os.symlink(ibus_desktop, link_file)
472 def __combobox_lookup_table_orientation_changed_cb(self, combobox):
473 self.__config.set_value(
474 "panel", "lookup_table_orientation",
475 GLib.Variant.new_int32(self.__combobox_lookup_table_orientation.get_active()))
477 def __combobox_panel_show_changed_cb(self, combobox):
478 self.__config.set_value(
480 GLib.Variant.new_int32(self.__combobox_panel_show.get_active()))
482 def __combobox_panel_position_changed_cb(self, combobox):
483 self.__config.set_value(
485 GLib.Variant.new_int32(self.__combobox_panel_position.get_active()))
487 def __checkbutton_custom_font_toggled_cb(self, button):
488 if self.__checkbutton_custom_font.get_active():
489 self.__fontbutton_custom_font.set_sensitive(True)
490 self.__config.set_value("panel", "use_custom_font",
491 GLib.Variant.new_boolean(True))
493 self.__fontbutton_custom_font.set_sensitive(False)
494 self.__config.set_value("panel", "use_custom_font",
495 GLib.Variant.new_boolean(False))
497 def __fontbutton_custom_font_notify_cb(self, button, arg):
498 font_name = self.__fontbutton_custom_font.get_font_name()
499 font_name = unicode(font_name, "utf-8")
500 self.__config.set_value("panel", "custom_font",
501 GLib.Variant.new_string(font_name))
503 def __checkbutton_show_icon_on_systray_toggled_cb(self, button):
504 value = self.__checkbutton_show_icon_on_systray.get_active()
505 value = GLib.Variant.new_boolean(value)
506 self.__config.set_value("panel", "show_icon_on_systray", value)
508 def __checkbutton_show_im_name_toggled_cb(self, button):
509 value = self.__checkbutton_show_im_name.get_active()
510 value = GLib.Variant.new_boolean(value)
511 self.__config.set_value("panel", "show_im_name", value)
513 def __checkbutton_embed_preedit_text_toggled_cb(self, button):
514 value = self.__checkbutton_embed_preedit_text.get_active()
515 value = GLib.Variant.new_boolean(value)
516 self.__config.set_value("general", "embed_preedit_text", value)
518 def __checkbutton_use_sys_layout_toggled_cb(self, button):
519 value = self.__checkbutton_use_sys_layout.get_active()
520 value = GLib.Variant.new_boolean(value)
521 self.__config.set_value("general", "use_system_keyboard_layout", value)
523 def __checkbutton_use_global_engine_toggled_cb(self, button):
524 value = self.__checkbutton_use_global_engine.get_active()
525 value = GLib.Variant.new_boolean(value)
526 self.__config.set_value("general", "use_global_engine", value)
528 def __config_value_changed_cb(self, bus, section, name, value):
531 def __config_reloaded_cb(self, bus):
534 def __sigusr1_cb(self, *args):
535 self.__window.present()
538 self.__window.show_all()
539 signal.signal(signal.SIGUSR1, self.__sigusr1_cb)
542 if __name__ == "__main__":
543 locale.setlocale(locale.LC_ALL, '')