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.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)
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):
320 self.__bus = IBus.Bus()
321 # self.__bus.connect("config-value-changed", self.__config_value_changed_cb)
322 # self.__bus.connect("config-reloaded", self.__config_reloaded_cb)
323 # self.__bus.config_add_watch("/general")
324 # self.__bus.config_add_watch("/general/hotkey")
325 # self.__bus.config_add_watch("/panel")
327 while self.__bus == None:
328 message = _("IBus daemon is not started. Do you want to start it now?")
329 dlg = Gtk.MessageDialog(type = Gtk.MESSAGE_QUESTION,
330 buttons = Gtk.ButtonsType.YES_NO,
331 message_format = message)
334 self.__flush_gtk_events()
335 if id != Gtk.ResponseType.YES:
337 pid = os.spawnlp(os.P_NOWAIT, "ibus-daemon", "ibus-daemon", "--xim")
340 self.__bus = IBus.Bus()
343 message = _("IBus has been started! "
344 "If you can not use IBus, please add below lines in $HOME/.bashrc, and relogin your desktop.\n"
345 " export GTK_IM_MODULE=ibus\n"
346 " export XMODIFIERS=@im=ibus\n"
347 " export QT_IM_MODULE=ibus"
349 dlg = Gtk.MessageDialog(type = Gtk.MESSAGE_INFO,
350 buttons = Gtk.ButtonsType.OK,
351 message_format = message)
354 self.__flush_gtk_events()
356 def __shortcut_button_clicked_cb(self, button, name, section, _name, entry):
357 buttons = (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
358 Gtk.STOCK_OK, Gtk.ResponseType.OK)
359 title = _("Select keyboard shortcut for %s") % _(name)
360 dialog = keyboardshortcut.KeyboardShortcutSelectionDialog(buttons = buttons, title = title)
361 text = entry.get_text()
363 shortcuts = text.split("; ")
366 dialog.set_shortcuts(shortcuts)
368 shortcuts = dialog.get_shortcuts()
370 if id != Gtk.ResponseType.OK:
372 self.__config.set_value(section, _name, GLib.Variant.new_strv(shortcuts))
373 text = "; ".join(shortcuts)
375 entry.set_tooltip_text(text)
378 def __item_started_column_toggled_cb(self, cell, path_str, model):
381 iter = model.get_iter_from_string(path_str)
382 data = model.get_value(iter, COLUMN_DATA)
384 # do something with the value
385 if data[DATA_STARTED] == False:
387 self.__bus.register_start_engine(data[DATA_LANG], data[DATA_NAME])
389 dlg = Gtk.MessageDialog(type = Gtk.MESSAGE_ERROR,
390 buttons = Gtk.ButtonsType.CLOSE,
391 message_format = str(e))
394 self.__flush_gtk_events()
398 self.__bus.register_stop_engine(data[DATA_LANG], data[DATA_NAME])
400 dlg = Gtk.MessageDialog(type = Gtk.MESSAGE_ERROR,
401 buttons = Gtk.ButtonsType.CLOSE,
402 message_format = str(e))
405 self.__flush_gtk_events()
407 data[DATA_STARTED] = not data[DATA_STARTED]
410 model.set(iter, COLUMN_ENABLE, data[DATA_STARTED])
412 def __item_preload_column_toggled_cb(self, cell, path_str, model):
415 iter = model.get_iter_from_string(path_str)
416 data = model.get_value(iter, COLUMN_DATA)
418 data[DATA_PRELOAD] = not data[DATA_PRELOAD]
419 engine = "%s:%s" % (data[DATA_LANG], data[DATA_NAME])
421 if data[DATA_PRELOAD]:
422 if engine not in self.__preload_engines:
423 self.__preload_engines.add(engine)
424 value = GLib.Variant.new_strv(list(self.__preload_engines))
425 self.__config.set_value("general", "preload_engines", value)
427 if engine in self.__preload_engines:
428 self.__preload_engines.remove(engine)
429 value = GLib.Variant.new_strv(list(self.__preload_engines))
430 self.__config.set_value("general", "preload_engines", value)
433 model.set(iter, COLUMN_PRELOAD, data[DATA_PRELOAD])
435 def __is_auto_start(self):
436 link_file = path.join(BaseDirectory.xdg_config_home, "autostart/IBus.desktop")
437 ibus_desktop = path.join(os.getenv("IBUS_PREFIX"), "share/applications/IBus.desktop")
439 if not path.exists(link_file):
441 if not path.islink(link_file):
443 if path.realpath(link_file) != ibus_desktop:
447 def __checkbutton_auto_start_toggled_cb(self, button):
448 auto_start_dir = path.join(BaseDirectory.xdg_config_home, "autostart")
449 if not path.isdir(auto_start_dir):
450 os.makedirs(auto_start_dir)
452 link_file = path.join(BaseDirectory.xdg_config_home, "autostart/IBus.desktop")
453 ibus_desktop = path.join(os.getenv("IBUS_PREFIX"), "share/applications/IBus.desktop")
459 if self.__checkbutton_auto_start.get_active():
460 os.symlink(ibus_desktop, link_file)
462 def __combobox_lookup_table_orientation_changed_cb(self, combobox):
463 self.__config.set_value(
464 "panel", "lookup_table_orientation",
465 GLib.Variant.new_int32(self.__combobox_lookup_table_orientation.get_active()))
467 def __combobox_panel_show_changed_cb(self, combobox):
468 self.__config.set_value(
470 GLib.Variant.new_int32(self.__combobox_panel_show.get_active()))
472 def __combobox_panel_position_changed_cb(self, combobox):
473 self.__config.set_value(
475 GLib.Variant.new_int32(self.__combobox_panel_position.get_active()))
477 def __checkbutton_custom_font_toggled_cb(self, button):
478 if self.__checkbutton_custom_font.get_active():
479 self.__fontbutton_custom_font.set_sensitive(True)
480 self.__config.set_value("panel", "use_custom_font",
481 GLib.Variant.new_boolean(True))
483 self.__fontbutton_custom_font.set_sensitive(False)
484 self.__config.set_value("panel", "use_custom_font",
485 GLib.Variant.new_boolean(False))
487 def __fontbutton_custom_font_notify_cb(self, button, arg):
488 font_name = self.__fontbutton_custom_font.get_font_name()
489 font_name = unicode(font_name, "utf-8")
490 self.__config.set_value("panel", "custom_font",
491 GLib.Variant.new_string(font_name))
493 def __checkbutton_show_icon_on_systray_toggled_cb(self, button):
494 value = self.__checkbutton_show_icon_on_systray.get_active()
495 value = GLib.Variant.new_boolean(value)
496 self.__config.set_value("panel", "show_icon_on_systray", value)
498 def __checkbutton_show_im_name_toggled_cb(self, button):
499 value = self.__checkbutton_show_im_name.get_active()
500 value = GLib.Variant.new_boolean(value)
501 self.__config.set_value("panel", "show_im_name", value)
503 def __checkbutton_embed_preedit_text_toggled_cb(self, button):
504 value = self.__checkbutton_embed_preedit_text.get_active()
505 value = GLib.Variant.new_boolean(value)
506 self.__config.set_value("general", "embed_preedit_text", value)
508 def __checkbutton_use_sys_layout_toggled_cb(self, button):
509 value = self.__checkbutton_use_sys_layout.get_active()
510 value = GLib.Variant.new_boolean(value)
511 self.__config.set_value("general", "use_system_keyboard_layout", value)
513 def __checkbutton_use_global_engine_toggled_cb(self, button):
514 value = self.__checkbutton_use_global_engine.get_active()
515 value = GLib.Variant.new_boolean(value)
516 self.__config.set_value("general", "use_global_engine", value)
518 def __config_value_changed_cb(self, bus, section, name, value):
521 def __config_reloaded_cb(self, bus):
524 def __sigusr1_cb(self, *args):
525 self.__window.present()
528 self.__window.show_all()
529 signal.signal(signal.SIGUSR1, self.__sigusr1_cb)
532 if __name__ == "__main__":
533 locale.setlocale(locale.LC_ALL, '')