1 # vim:set et sts=4 sw=4:
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
26 from xdg import BaseDirectory
30 from gtk import gdk, glade
31 import keyboardshortcut
33 from gettext import dgettext
34 _ = lambda a : dgettext("ibus", a)
58 CONFIG_GENERAL_SHORTCUT = "/general/keyboard_shortcut_%s"
59 CONFIG_PRELOAD_ENGINES = "/general/preload_engines"
60 CONFIG_PANEL_LOOKUP_TABLE_ORIENTATION = "/panel/lookup_table_orientation"
61 CONFIG_PANEL_AUTO_HIDE = "/panel/auto_hide"
62 CONFIG_PANEL_USE_CUSTOM_FONT = "/panel/use_custom_font"
63 CONFIG_PANEL_CUSTOM_FONT = "/panel/custom_font"
66 def __flush_gtk_events(self):
67 while gtk.events_pending():
71 super(Setup, self).__init__()
72 glade.textdomain("ibus")
73 glade_file = path.join(path.dirname(__file__), "./setup.glade")
74 self.__xml = glade.XML(glade_file)
80 # add icon search path
81 icon_theme = gtk.icon_theme_get_default()
82 dir = path.dirname(__file__)
83 icondir = path.join(dir, "..", "icons")
84 icon_theme.prepend_search_path(icondir)
87 self.__dialog = self.__xml.get_widget("dialog_setup")
90 self.__checkbutton_auto_start = self.__xml.get_widget("checkbutton_auto_start")
91 self.__checkbutton_auto_start.set_active(self.__is_auto_start())
92 self.__checkbutton_auto_start.connect("toggled", self.__checkbutton_auto_start_toggled_cb)
95 for name in (N_("trigger"), N_("next_engine"), N_("prev_engine")):
96 shortcuts = self.__bus.config_get_value(CONFIG_GENERAL_SHORTCUT % name, [])
97 button = self.__xml.get_widget("button_%s" % name)
98 entry = self.__xml.get_widget("entry_%s" % name)
99 entry.set_text(";".join(shortcuts))
100 button.connect("clicked", self.__shortcut_button_clicked_cb, name, entry)
102 # lookup table orientation
103 self.__combobox_lookup_table_orientation = self.__xml.get_widget("combobox_lookup_table_orientation")
104 self.__combobox_lookup_table_orientation.set_active(
105 self.__bus.config_get_value(CONFIG_PANEL_LOOKUP_TABLE_ORIENTATION, 0))
106 self.__combobox_lookup_table_orientation.connect("changed",
107 self.__combobox_lookup_table_orientation_changed_cb)
110 self.__checkbutton_auto_hide = self.__xml.get_widget("checkbutton_auto_hide")
111 self.__checkbutton_auto_hide.set_active(
112 self.__bus.config_get_value(CONFIG_PANEL_AUTO_HIDE, False))
113 self.__checkbutton_auto_hide.connect("toggled", self.__checkbutton_auto_hide_toggled_cb)
116 self.__checkbutton_custom_font = self.__xml.get_widget("checkbutton_custom_font")
117 self.__checkbutton_custom_font.set_active(
118 self.__bus.config_get_value(CONFIG_PANEL_USE_CUSTOM_FONT, False))
119 self.__checkbutton_custom_font.connect("toggled", self.__checkbutton_custom_font_toggled_cb)
121 self.__fontbutton_custom_font = self.__xml.get_widget("fontbutton_custom_font")
122 if self.__bus.config_get_value(CONFIG_PANEL_USE_CUSTOM_FONT, False):
123 self.__fontbutton_custom_font.set_sensitive(True)
125 self.__fontbutton_custom_font.set_sensitive(False)
126 font_name = gtk.settings_get_default().get_property("gtk-font-name")
127 font_name = unicode(font_name, "utf-8")
128 font_name = self.__bus.config_get_value(CONFIG_PANEL_CUSTOM_FONT, font_name)
129 self.__fontbutton_custom_font.connect("notify::font-name", self.__fontbutton_custom_font_notify_cb)
130 self.__fontbutton_custom_font.set_font_name(font_name)
132 self.__init_engine_view()
134 def __init_bus(self):
136 self.__bus = ibus.Bus()
137 self.__bus.connect("config-value-changed", self.__config_value_changed_cb)
138 self.__bus.connect("config-reloaded", self.__config_reloaded_cb)
139 self.__bus.config_add_watch("/general")
140 self.__bus.config_add_watch("/panel")
142 while self.__bus == None:
143 message = _("IBus daemon is not started. Do you want to start it now?")
144 print >> sys.stderr, message
145 dlg = gtk.MessageDialog(type = gtk.MESSAGE_QUESTION,
146 buttons = gtk.BUTTONS_YES_NO,
147 message_format = message)
150 self.__flush_gtk_events()
151 if id != gtk.RESPONSE_YES:
153 pid = os.spawnlp(os.P_NOWAIT, "ibus", "ibus")
156 self.__bus = ibus.Bus()
159 message = _("IBus has been started! " + \
160 "If you can not use IBus, please add below lines in $HOME/.bashrc, and relogin your desktop.\n" + \
161 " export GTK_IM_MODULE=ibus\n" + \
162 " export XMODIFIERS=@im=ibus\n"
163 " export QT_IM_MODULE=ibus"
165 dlg = gtk.MessageDialog(type = gtk.MESSAGE_INFO,
166 buttons = gtk.BUTTONS_OK,
167 message_format = message)
170 self.__flush_gtk_events()
172 def __init_engine_view(self):
174 self.__tree = self.__xml.get_widget("treeview_engines")
175 self.__preload_engines = set(self.__bus.config_get_value(CONFIG_PRELOAD_ENGINES, []))
176 model = self.__create_model()
177 self.__tree.set_model(model)
180 column = gtk.TreeViewColumn()
181 column.set_title(_("Engine"))
183 renderer = gtk.CellRendererPixbuf()
184 renderer.set_property("xalign", 0.5)
186 column.pack_start(renderer)
187 column.set_attributes(renderer, pixbuf = COLUMN_ICON, visible = COLUMN_VISIBLE)
189 renderer = gtk.CellRendererText()
190 renderer.set_property("xalign", 0.0)
192 # column.set_clickable(True)
193 column.pack_start(renderer)
194 column.set_attributes(renderer, text = COLUMN_NAME)
196 self.__tree.append_column(column)
199 renderer = gtk.CellRendererToggle()
200 renderer.set_data('column', COLUMN_ENABLE)
201 renderer.set_property("xalign", 0.5)
202 renderer.connect("toggled", self.__item_started_column_toggled_cb, model)
204 #col_offset = gtk.TreeViewColumn("Holiday", renderer, text=HOLIDAY_NAME)
205 column = gtk.TreeViewColumn(_("Started"), renderer, active = COLUMN_ENABLE, visible = COLUMN_VISIBLE)
206 self.__tree.append_column(column)
209 renderer = gtk.CellRendererToggle()
210 renderer.set_data('column', COLUMN_PRELOAD)
211 renderer.set_property("xalign", 0.5)
212 renderer.connect("toggled", self.__item_preload_column_toggled_cb, model)
214 column = gtk.TreeViewColumn(_("Preload"), renderer, active = COLUMN_PRELOAD, visible = COLUMN_VISIBLE)
215 self.__tree.append_column(column)
217 renderer = gtk.CellRendererText()
218 column = gtk.TreeViewColumn("", renderer)
219 self.__tree.append_column(column)
221 def __shortcut_button_clicked_cb(self, button, name, entry):
222 buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)
223 title = _("Select keyboard shortcut for %s") % _(name)
224 dialog = keyboardshortcut.KeyboardShortcutSelectionDialog(buttons = buttons, title = title)
225 text = entry.get_text()
227 shortcuts = text.split(';')
230 dialog.set_shortcuts(shortcuts)
232 shortcuts = list(set(dialog.get_shortcuts()))
234 if id != gtk.RESPONSE_OK:
236 self.__bus.config_set_value(CONFIG_GENERAL_SHORTCUT % name, shortcuts)
237 entry.set_text(";".join(shortcuts))
240 def __item_started_column_toggled_cb(self, cell, path_str, model):
243 iter = model.get_iter_from_string(path_str)
244 data = model.get_value(iter, COLUMN_DATA)
246 # do something with the value
247 if data[DATA_STARTED] == False:
249 self.__bus.register_start_engine(data[DATA_LANG], data[DATA_NAME])
251 dlg = gtk.MessageDialog(type = gtk.MESSAGE_ERROR,
252 buttons = gtk.BUTTONS_CLOSE,
253 message_format = str(e))
256 self.__flush_gtk_events()
260 self.__bus.register_stop_engine(data[DATA_LANG], data[DATA_NAME])
262 dlg = gtk.MessageDialog(type = gtk.MESSAGE_ERROR,
263 buttons = gtk.BUTTONS_CLOSE,
264 message_format = str(e))
267 self.__flush_gtk_events()
269 data[DATA_STARTED] = not data[DATA_STARTED]
272 model.set(iter, COLUMN_ENABLE, data[DATA_STARTED])
274 def __item_preload_column_toggled_cb(self, cell, path_str, model):
277 iter = model.get_iter_from_string(path_str)
278 data = model.get_value(iter, COLUMN_DATA)
280 data[DATA_PRELOAD] = not data[DATA_PRELOAD]
281 engine = "%s:%s" % (data[DATA_LANG], data[DATA_NAME])
283 if data[DATA_PRELOAD]:
284 if engine not in self.__preload_engines:
285 self.__preload_engines.add(engine)
286 self.__bus.config_set_list(CONFIG_PRELOAD_ENGINES, list(self.__preload_engines), "s")
288 if engine in self.__preload_engines:
289 self.__preload_engines.remove(engine)
290 self.__bus.config_set_list(CONFIG_PRELOAD_ENGINES, list(self.__preload_engines), "s")
294 model.set(iter, COLUMN_PRELOAD, data[DATA_PRELOAD])
296 def __load_icon(self, icon, icon_size):
299 pixbuf = gdk.pixbuf_new_from_file(icon)
300 w, h = pixbuf.get_width(), pixbuf.get_height()
301 rate = max(w, h) / float(icon_size)
304 pixbuf = pixbuf.scale_simple(w, h, gdk.INTERP_BILINEAR)
309 theme = gtk.icon_theme_get_default()
310 pixbuf = theme.load_icon(icon, icon_size, 0)
315 def __create_model(self):
317 model = gtk.TreeStore(
319 gobject.TYPE_BOOLEAN,
320 gobject.TYPE_BOOLEAN,
321 gobject.TYPE_BOOLEAN,
323 gobject.TYPE_PYOBJECT)
327 self.__bus.register_reload_engines()
328 for name, local_name, lang, icon, author, credits, _exec, started in self.__bus.register_list_engines():
329 _lang = ibus.LANGUAGES.get(lang, "other")
331 if _lang not in langs:
332 langs[_lang] = list()
333 langs[_lang].append([name, local_name, lang, icon, author, credits, _exec, started])
338 icon_size = gtk.icon_size_lookup(gtk.ICON_SIZE_LARGE_TOOLBAR)[0]
339 pixbuf_missing = self.__load_icon("engine-default", icon_size)
340 if pixbuf_missing == None:
341 pixbuf_missing = self.__load_icon("gtk-missing-image", icon_size)
344 iter = model.append(None)
347 COLUMN_ENABLE, False,
348 COLUMN_PRELOAD, False,
349 COLUMN_VISIBLE, False,
354 for name, local_name, lang, icon, author, credits, _exec, started in langs[key]:
355 child_iter = model.append(iter)
356 is_preload = "%s:%s" % (lang, name) in self.__preload_engines
358 pixbuf = self.__load_icon(icon, icon_size)
360 pixbuf = pixbuf_missing
362 model.set(child_iter,
363 COLUMN_NAME, local_name,
364 COLUMN_ENABLE, started,
365 COLUMN_PRELOAD, is_preload,
366 COLUMN_VISIBLE, True,
369 [name, local_name, lang, icon, author, credits, _exec, started, is_preload])
373 def __is_auto_start(self):
374 link_file = path.join(BaseDirectory.xdg_config_home, "autostart/ibus.desktop")
375 ibus_desktop = path.join(os.getenv("IBUS_PREFIX"), "share/applications/ibus.desktop")
377 if not path.exists(link_file):
379 if not path.islink(link_file):
381 if path.realpath(link_file) != ibus_desktop:
385 def __checkbutton_auto_start_toggled_cb(self, button):
386 auto_start_dir = path.join(BaseDirectory.xdg_config_home, "autostart")
387 if not path.isdir(auto_start_dir):
388 os.makedirs(auto_start_dir)
390 link_file = path.join(BaseDirectory.xdg_config_home, "autostart/ibus.desktop")
391 ibus_desktop = path.join(os.getenv("IBUS_PREFIX"), "share/applications/ibus.desktop")
397 if self.__checkbutton_auto_start.get_active():
398 os.symlink(ibus_desktop, link_file)
400 def __combobox_lookup_table_orientation_changed_cb(self, combobox):
401 self.__bus.config_set_value(
402 CONFIG_PANEL_LOOKUP_TABLE_ORIENTATION,
403 self.__combobox_lookup_table_orientation.get_active())
405 def __checkbutton_auto_hide_toggled_cb(self, button):
406 self.__bus.config_set_value(
407 CONFIG_PANEL_AUTO_HIDE,
408 self.__checkbutton_auto_hide.get_active())
410 def __checkbutton_custom_font_toggled_cb(self, button):
411 if self.__checkbutton_custom_font.get_active():
412 self.__fontbutton_custom_font.set_sensitive(True)
413 self.__bus.config_set_value(CONFIG_PANEL_USE_CUSTOM_FONT, True)
415 self.__fontbutton_custom_font.set_sensitive(False)
416 self.__bus.config_set_value(CONFIG_PANEL_USE_CUSTOM_FONT, False)
418 def __fontbutton_custom_font_notify_cb(self, button, arg):
419 font_name = self.__fontbutton_custom_font.get_font_name()
420 font_name = unicode(font_name, "utf-8")
421 self.__bus.config_set_value(CONFIG_PANEL_CUSTOM_FONT, font_name)
423 def __config_value_changed_cb(self, bus, key, value):
424 if key == CONFIG_PANEL_LOOKUP_TABLE_ORIENTATION:
425 item = self.__bus.config_get_value(CONFIG_PANEL_LOOKUP_TABLE_ORIENTATION, 0)
426 if item != 0 and item != 1:
428 self.__combobox_lookup_table_orientation.set_active(item)
430 def __config_reloaded_cb(self, bus):
434 return self.__dialog.run()
436 if __name__ == "__main__":