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):
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")
329 if self.__bus != None and self.__bus.is_connected():
331 while self.__bus == None or not self.__bus.is_connected():
332 message = _("IBus daemon is not started. Do you want to start it now?")
333 dlg = Gtk.MessageDialog(type = Gtk.MessageType.QUESTION,
334 buttons = Gtk.ButtonsType.YES_NO,
335 message_format = message)
338 self.__flush_gtk_events()
339 if id != Gtk.ResponseType.YES:
341 pid = os.spawnlp(os.P_NOWAIT, "ibus-daemon", "ibus-daemon", "--xim")
344 if self.__bus != None:
346 self.__bus = IBus.Bus()
349 message = _("IBus has been started! "
350 "If you can not use IBus, please add below lines in $HOME/.bashrc, and relogin your desktop.\n"
351 " export GTK_IM_MODULE=ibus\n"
352 " export XMODIFIERS=@im=ibus\n"
353 " export QT_IM_MODULE=ibus"
355 dlg = Gtk.MessageDialog(type = Gtk.MessageType.INFO,
356 buttons = Gtk.ButtonsType.OK,
357 message_format = message)
360 self.__flush_gtk_events()
362 def __shortcut_button_clicked_cb(self, button, name, section, _name, entry):
363 buttons = (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
364 Gtk.STOCK_OK, Gtk.ResponseType.OK)
365 title = _("Select keyboard shortcut for %s") % _(name)
366 dialog = keyboardshortcut.KeyboardShortcutSelectionDialog(buttons = buttons, title = title)
367 text = entry.get_text()
369 shortcuts = text.split("; ")
372 dialog.set_shortcuts(shortcuts)
374 shortcuts = dialog.get_shortcuts()
376 if id != Gtk.ResponseType.OK:
378 self.__config.set_value(section, _name, GLib.Variant.new_strv(shortcuts))
379 text = "; ".join(shortcuts)
381 entry.set_tooltip_text(text)
384 def __item_started_column_toggled_cb(self, cell, path_str, model):
387 iter = model.get_iter_from_string(path_str)
388 data = model.get_value(iter, COLUMN_DATA)
390 # do something with the value
391 if data[DATA_STARTED] == False:
393 self.__bus.register_start_engine(data[DATA_LANG], data[DATA_NAME])
395 dlg = Gtk.MessageDialog(type = Gtk.MESSAGE_ERROR,
396 buttons = Gtk.ButtonsType.CLOSE,
397 message_format = str(e))
400 self.__flush_gtk_events()
404 self.__bus.register_stop_engine(data[DATA_LANG], data[DATA_NAME])
406 dlg = Gtk.MessageDialog(type = Gtk.MESSAGE_ERROR,
407 buttons = Gtk.ButtonsType.CLOSE,
408 message_format = str(e))
411 self.__flush_gtk_events()
413 data[DATA_STARTED] = not data[DATA_STARTED]
416 model.set(iter, COLUMN_ENABLE, data[DATA_STARTED])
418 def __item_preload_column_toggled_cb(self, cell, path_str, model):
421 iter = model.get_iter_from_string(path_str)
422 data = model.get_value(iter, COLUMN_DATA)
424 data[DATA_PRELOAD] = not data[DATA_PRELOAD]
425 engine = "%s:%s" % (data[DATA_LANG], data[DATA_NAME])
427 if data[DATA_PRELOAD]:
428 if engine not in self.__preload_engines:
429 self.__preload_engines.add(engine)
430 value = GLib.Variant.new_strv(list(self.__preload_engines))
431 self.__config.set_value("general", "preload_engines", value)
433 if engine in self.__preload_engines:
434 self.__preload_engines.remove(engine)
435 value = GLib.Variant.new_strv(list(self.__preload_engines))
436 self.__config.set_value("general", "preload_engines", value)
439 model.set(iter, COLUMN_PRELOAD, data[DATA_PRELOAD])
441 def __is_auto_start(self):
442 link_file = path.join(BaseDirectory.xdg_config_home, "autostart/IBus.desktop")
443 ibus_desktop = path.join(os.getenv("IBUS_PREFIX"), "share/applications/IBus.desktop")
445 if not path.exists(link_file):
447 if not path.islink(link_file):
449 if path.realpath(link_file) != ibus_desktop:
453 def __checkbutton_auto_start_toggled_cb(self, button):
454 auto_start_dir = path.join(BaseDirectory.xdg_config_home, "autostart")
455 if not path.isdir(auto_start_dir):
456 os.makedirs(auto_start_dir)
458 link_file = path.join(BaseDirectory.xdg_config_home, "autostart/IBus.desktop")
459 ibus_desktop = path.join(os.getenv("IBUS_PREFIX"), "share/applications/IBus.desktop")
465 if self.__checkbutton_auto_start.get_active():
466 os.symlink(ibus_desktop, link_file)
468 def __combobox_lookup_table_orientation_changed_cb(self, combobox):
469 self.__config.set_value(
470 "panel", "lookup_table_orientation",
471 GLib.Variant.new_int32(self.__combobox_lookup_table_orientation.get_active()))
473 def __combobox_panel_show_changed_cb(self, combobox):
474 self.__config.set_value(
476 GLib.Variant.new_int32(self.__combobox_panel_show.get_active()))
478 def __combobox_panel_position_changed_cb(self, combobox):
479 self.__config.set_value(
481 GLib.Variant.new_int32(self.__combobox_panel_position.get_active()))
483 def __checkbutton_custom_font_toggled_cb(self, button):
484 if self.__checkbutton_custom_font.get_active():
485 self.__fontbutton_custom_font.set_sensitive(True)
486 self.__config.set_value("panel", "use_custom_font",
487 GLib.Variant.new_boolean(True))
489 self.__fontbutton_custom_font.set_sensitive(False)
490 self.__config.set_value("panel", "use_custom_font",
491 GLib.Variant.new_boolean(False))
493 def __fontbutton_custom_font_notify_cb(self, button, arg):
494 font_name = self.__fontbutton_custom_font.get_font_name()
495 font_name = unicode(font_name, "utf-8")
496 self.__config.set_value("panel", "custom_font",
497 GLib.Variant.new_string(font_name))
499 def __checkbutton_show_icon_on_systray_toggled_cb(self, button):
500 value = self.__checkbutton_show_icon_on_systray.get_active()
501 value = GLib.Variant.new_boolean(value)
502 self.__config.set_value("panel", "show_icon_on_systray", value)
504 def __checkbutton_show_im_name_toggled_cb(self, button):
505 value = self.__checkbutton_show_im_name.get_active()
506 value = GLib.Variant.new_boolean(value)
507 self.__config.set_value("panel", "show_im_name", value)
509 def __checkbutton_embed_preedit_text_toggled_cb(self, button):
510 value = self.__checkbutton_embed_preedit_text.get_active()
511 value = GLib.Variant.new_boolean(value)
512 self.__config.set_value("general", "embed_preedit_text", value)
514 def __checkbutton_use_sys_layout_toggled_cb(self, button):
515 value = self.__checkbutton_use_sys_layout.get_active()
516 value = GLib.Variant.new_boolean(value)
517 self.__config.set_value("general", "use_system_keyboard_layout", value)
519 def __checkbutton_use_global_engine_toggled_cb(self, button):
520 value = self.__checkbutton_use_global_engine.get_active()
521 value = GLib.Variant.new_boolean(value)
522 self.__config.set_value("general", "use_global_engine", value)
524 def __config_value_changed_cb(self, bus, section, name, value):
527 def __config_reloaded_cb(self, bus):
530 def __sigusr1_cb(self, *args):
531 self.__window.present()
534 self.__window.show_all()
535 signal.signal(signal.SIGUSR1, self.__sigusr1_cb)
538 if __name__ == "__main__":
539 locale.setlocale(locale.LC_ALL, '')