PageRenderTime 114ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/ui/gtk/panel.py

https://github.com/iwaim/ibus
Python | 411 lines | 337 code | 49 blank | 25 comment | 20 complexity | a1026d2aaa50f19cde155011ef654516 MD5 | raw file
Possible License(s): LGPL-2.1
  1. # vim:set et sts=4 sw=4:
  2. #
  3. # ibus - The Input Bus
  4. #
  5. # Copyright(c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
  6. #
  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.
  11. #
  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.
  16. #
  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
  21. import gtk
  22. import gtk.gdk as gdk
  23. import gobject
  24. import ibus
  25. import icon as _icon
  26. import os
  27. import sys
  28. import signal
  29. from os import path
  30. from ibus import interface
  31. from languagebar import LanguageBar
  32. from candidatepanel import CandidatePanel
  33. from gettext import dgettext
  34. _ = lambda a : dgettext("ibus", a)
  35. N_ = lambda a : a
  36. def show_uri(screen, link):
  37. try:
  38. gtk.show_uri(screen, link, 0)
  39. except:
  40. print >> sys.stderr, "pygtk do not support show_uri"
  41. def url_hook(about, link, user_data):
  42. show_uri(about.get_screen(), link)
  43. def email_hook(about, email, user_data):
  44. show_uri(about.get_screen(), "mailto:%s" % email)
  45. gtk.about_dialog_set_url_hook(url_hook, None)
  46. gtk.about_dialog_set_email_hook(email_hook, None)
  47. class Panel(ibus.PanelBase):
  48. def __init__ (self, bus):
  49. super(Panel, self).__init__(bus)
  50. self.__bus = bus
  51. self.__config = self.__bus.get_config()
  52. self.__focus_ic = None
  53. self.__setup_pid = 0
  54. self.__prefix = os.getenv("IBUS_PREFIX")
  55. self.__data_dir = path.join(self.__prefix, "share", "ibus")
  56. self.__icons_dir = path.join(self.__data_dir, "icons")
  57. self.__ibus_icon = path.join(self.__icons_dir, "ibus.svg")
  58. self.__setup_cmd = path.join(self.__prefix, "bin", "ibus-setup")
  59. # hanlder signal
  60. signal.signal(signal.SIGCHLD, self.__sigchld_cb)
  61. # connect bus signal
  62. self.__config.connect("value-changed", self.__config_value_changed_cb)
  63. self.__config.connect("reloaded", self.__config_reloaded_cb)
  64. # self.__bus.config_add_watch("panel")
  65. # add icon search path
  66. icon_theme = gtk.icon_theme_get_default()
  67. icon_theme.prepend_search_path(self.__icons_dir)
  68. self.__language_bar = LanguageBar()
  69. self.__language_bar.connect("property-activate",
  70. lambda widget, prop_name, prop_state: self.property_activate(prop_name, prop_state))
  71. self.__language_bar.connect("get-im-menu",
  72. self.__get_im_menu_cb)
  73. self.__language_bar.focus_out()
  74. self.__language_bar.show_all()
  75. self.__candidate_panel = CandidatePanel()
  76. self.__candidate_panel.connect("cursor-up",
  77. lambda widget: self.cursor_up())
  78. self.__candidate_panel.connect("cursor-down",
  79. lambda widget: self.cursor_down())
  80. self.__status_icon = gtk.StatusIcon()
  81. self.__status_icon.connect("popup-menu", self.__status_icon_popup_menu_cb)
  82. self.__status_icon.connect("activate", self.__status_icon_activate_cb)
  83. self.__status_icon.set_from_file(self.__ibus_icon)
  84. self.__status_icon.set_tooltip(_("IBus input method framework"))
  85. self.__status_icon.set_visible(True)
  86. self.__config_load_lookup_table_orientation()
  87. self.__config_load_show()
  88. self.__config_load_custom_font()
  89. # self.__bus.request_name(ibus.panel.IBUS_SERVICE_PANEL, 0)
  90. def set_cursor_location(self, x, y, w, h):
  91. self.__candidate_panel.set_cursor_location(x + w, y + h)
  92. def update_preedit_text(self, text, cursor_pos, visible):
  93. self.__candidate_panel.update_preedit_text(text, cursor_pos, visible)
  94. def show_preedit_text(self):
  95. self.__candidate_panel.show_preedit_text()
  96. def hide_preedit_text(self):
  97. self.__candidate_panel.hide_preedit_text()
  98. def update_auxiliary_text(self, text, visible):
  99. self.__candidate_panel.update_auxiliary_text(text, visible)
  100. def show_auxiliary_text(self):
  101. self.__candidate_panel.show_auxiliary_text()
  102. def hide_auxiliary_text(self):
  103. self.__candidate_panel.hide_auxiliary_text()
  104. def update_lookup_table(self, lookup_table, visible):
  105. self.__candidate_panel.update_lookup_table(lookup_table, visible)
  106. def show_lookup_table(self):
  107. self.__candidate_panel.show_lookup_table()
  108. def hide_lookup_table(self):
  109. self.__candidate_panel.hide_lookup_table()
  110. def page_up_lookup_table(self):
  111. self.__candidate_panel.page_up_lookup_table()
  112. def page_down_lookup_table(self):
  113. self.__candidate_panel.page_down_lookup_table()
  114. def cursor_up_lookup_table(self):
  115. self.__candidate_panel.cursor_up_lookup_table()
  116. def cursor_down_lookup_table(self):
  117. self.__candidate_panel.cursor_down_lookup_table()
  118. def show_candidate_window(self):
  119. self.__candidate_panel.show_all()
  120. def hide_candidate_window(self):
  121. self.__candidate_panel.hide_all()
  122. def show_language_bar(self):
  123. self.__language_bar.show_all()
  124. def hide_language_bar(self):
  125. self.__language_bar.hide_all()
  126. def register_properties(self, props):
  127. self.__language_bar.register_properties(props)
  128. def update_property(self, prop):
  129. self.__language_bar.update_property(prop)
  130. def get_status_icon(self):
  131. return self.__status_icon
  132. def __set_im_icon(self, icon_name):
  133. if not icon_name:
  134. icon_name = "engine-default"
  135. self.__language_bar.set_im_icon(icon_name)
  136. if icon_name.startswith("/"):
  137. self.__status_icon.set_from_file(icon_name)
  138. else:
  139. self.__status_icon.set_from_icon_name(icon_name)
  140. def focus_in(self, ic):
  141. self.reset()
  142. self.__focus_ic = ibus.InputContext(self.__bus, ic)
  143. enabled = self.__focus_ic.is_enabled()
  144. self.__language_bar.set_enabled(enabled)
  145. if not enabled:
  146. self.__set_im_icon(self.__ibus_icon)
  147. else:
  148. engine = self.__focus_ic.get_engine()
  149. if engine:
  150. self.__set_im_icon(engine.icon)
  151. else:
  152. self.__set_im_icon(self.__ibus_icon)
  153. self.__language_bar.focus_in()
  154. def focus_out(self, ic):
  155. self.reset()
  156. self.__focus_ic = None
  157. self.__language_bar.set_enabled(False)
  158. self.__language_bar.focus_out()
  159. self.__set_im_icon(self.__ibus_icon)
  160. def state_changed(self):
  161. if not self.__focus_ic:
  162. return
  163. enabled = self.__focus_ic.is_enabled()
  164. self.__language_bar.set_enabled(enabled)
  165. if enabled == False:
  166. self.reset()
  167. self.__set_im_icon(self.__ibus_icon)
  168. else:
  169. engine = self.__focus_ic.get_engine()
  170. if engine:
  171. self.__set_im_icon(engine.icon)
  172. else:
  173. self.__set_im_icon(self.__ibus_icon)
  174. def reset(self):
  175. self.__candidate_panel.reset()
  176. self.__language_bar.reset()
  177. def start_setup(self):
  178. self.__start_setup()
  179. def do_destroy(self):
  180. gtk.main_quit()
  181. def __config_load_lookup_table_orientation(self):
  182. value = self.__config.get_value("panel", "lookup_table_orientation", 0)
  183. if value != 0 and value != 1:
  184. value = 0
  185. if value == 0:
  186. self.__candidate_panel.set_orientation(gtk.ORIENTATION_HORIZONTAL)
  187. else:
  188. self.__candidate_panel.set_orientation(gtk.ORIENTATION_VERTICAL)
  189. def __config_load_show(self):
  190. show = self.__config.get_value("panel", "show", 1)
  191. self.__language_bar.set_show(show)
  192. def __config_load_custom_font(self):
  193. use_custom_font = self.__config.get_value("panel", "use_custom_font", False)
  194. font_name = gtk.settings_get_default().get_property("gtk-font-name")
  195. font_name = unicode(font_name, "utf-8")
  196. custom_font = self.__config.get_value("panel", "custom_font", font_name)
  197. style_string = 'style "custom-font" { font_name="%s" }\n' \
  198. 'class "IBusPanelLabel" style "custom-font"\n'
  199. if use_custom_font:
  200. style_string = style_string % custom_font
  201. gtk.rc_parse_string(style_string)
  202. else:
  203. style_string = style_string % ""
  204. gtk.rc_parse_string(style_string)
  205. settings = gtk.settings_get_default()
  206. gtk.rc_reset_styles(settings)
  207. def __config_value_changed_cb(self, bus, section, name, value):
  208. if section != "panel":
  209. return
  210. if name == "lookup_table_orientation":
  211. self.__config_load_lookup_table_orientation()
  212. elif name == "show":
  213. self.__config_load_show()
  214. elif name == "use_custom_font" or name == "custom_font":
  215. self.__config_load_custom_font()
  216. def __config_reloaded_cb(self, bus):
  217. pass
  218. def __create_sys_menu(self):
  219. menu = gtk.Menu()
  220. item = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
  221. item.connect("activate",
  222. self.__sys_menu_item_activate_cb, gtk.STOCK_PREFERENCES)
  223. menu.add(item)
  224. item = gtk.ImageMenuItem(gtk.STOCK_ABOUT)
  225. item.connect("activate",
  226. self.__sys_menu_item_activate_cb, gtk.STOCK_ABOUT)
  227. menu.add(item)
  228. menu.add(gtk.SeparatorMenuItem())
  229. item = gtk.MenuItem(_("Restart"))
  230. item.connect("activate",
  231. self.__sys_menu_item_activate_cb, "Restart")
  232. menu.add(item)
  233. item = gtk.ImageMenuItem(gtk.STOCK_QUIT)
  234. item.connect("activate",
  235. self.__sys_menu_item_activate_cb, gtk.STOCK_QUIT)
  236. menu.add(item)
  237. menu.show_all()
  238. menu.set_take_focus(False)
  239. return menu
  240. def __create_im_menu(self):
  241. menu = gtk.Menu()
  242. engines = self.__bus.list_active_engines()
  243. tmp = {}
  244. for engine in engines:
  245. lang = ibus.get_language_name(engine.language)
  246. if lang not in tmp:
  247. tmp[lang] = []
  248. tmp[lang].append(engine)
  249. langs = tmp.keys()
  250. other = tmp.get(_("Other"), [])
  251. if _("Other") in tmp:
  252. langs.remove(_("Other"))
  253. langs.append(_("Other"))
  254. size = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU)
  255. for lang in langs:
  256. if len(tmp[lang]) == 1:
  257. engine = tmp[lang][0]
  258. item = gtk.ImageMenuItem("%s - %s" % (lang, engine.longname))
  259. if engine.icon:
  260. item.set_image (_icon.IconWidget(engine.icon, size[0]))
  261. else:
  262. item.set_image (_icon.IconWidget("engine-default", size[0]))
  263. item.connect("activate", self.__im_menu_item_activate_cb, engine)
  264. menu.add(item)
  265. else:
  266. item = gtk.MenuItem(lang)
  267. menu.add(item)
  268. submenu = gtk.Menu()
  269. item.set_submenu(submenu)
  270. for engine in tmp[lang]:
  271. item = gtk.ImageMenuItem(engine.longname)
  272. if engine.icon:
  273. item.set_image (_icon.IconWidget(engine.icon, size[0]))
  274. else:
  275. item.set_image (_icon.IconWidget("engine-default", size[0]))
  276. item.connect("activate", self.__im_menu_item_activate_cb, engine)
  277. submenu.add(item)
  278. item = gtk.ImageMenuItem(_("No input method"))
  279. item.set_image (_icon.IconWidget("gtk-close", size[0]))
  280. item.connect("activate", self.__im_menu_item_activate_cb, None)
  281. menu.add (item)
  282. menu.show_all()
  283. menu.set_take_focus(False)
  284. return menu
  285. def __get_im_menu_cb(self, languagebar):
  286. menu = self.__create_im_menu()
  287. return menu
  288. def __status_icon_popup_menu_cb(self, status_icon, button, active_time):
  289. menu = self.__create_sys_menu()
  290. menu.popup(None, None,
  291. gtk.status_icon_position_menu,
  292. button,
  293. active_time,
  294. self.__status_icon)
  295. def __status_icon_activate_cb(self, status_icon):
  296. if not self.__focus_ic:
  297. return
  298. menu = self.__create_im_menu()
  299. menu.popup(None, None,
  300. gtk.status_icon_position_menu,
  301. 0,
  302. gtk.get_current_event_time(),
  303. self.__status_icon)
  304. def __im_menu_item_activate_cb(self, item, engine):
  305. if engine:
  306. self.__focus_ic.set_engine(engine)
  307. else:
  308. self.__focus_ic.disable()
  309. def __sys_menu_item_activate_cb(self, item, command):
  310. if command == gtk.STOCK_PREFERENCES:
  311. self.__start_setup()
  312. elif command == gtk.STOCK_ABOUT:
  313. about_dialog = gtk.AboutDialog()
  314. about_dialog.set_program_name("IBus")
  315. about_dialog.set_version(ibus.get_version())
  316. about_dialog.set_copyright(ibus.get_copyright())
  317. about_dialog.set_license(ibus.get_license())
  318. about_dialog.set_comments(_("IBus is an intelligent input bus for Linux/Unix."))
  319. about_dialog.set_website("http://code.google.com/p/ibus")
  320. about_dialog.set_authors(["Huang Peng <shawn.p.huang@gmail.com>"])
  321. about_dialog.set_documenters(["Huang Peng <shawn.p.huang@gmail.com>"])
  322. about_dialog.set_translator_credits(_("translator-credits"))
  323. about_dialog.set_logo_icon_name("ibus")
  324. about_dialog.run()
  325. about_dialog.destroy()
  326. elif command == gtk.STOCK_QUIT:
  327. self.__bus.exit(False)
  328. elif command == "Restart":
  329. self.__bus.exit(True)
  330. else:
  331. print >> sys.stderr, "Unknown command %s" % command
  332. def __sigchld_cb(self, sig, sf):
  333. pid, status = os.wait()
  334. if self.__setup_pid == pid:
  335. self.__setup_pid = 0
  336. def __start_setup(self):
  337. if self.__setup_pid != 0:
  338. pid, state = os.waitpid(self.__setup_pid, os.P_NOWAIT)
  339. if pid != self.__setup_pid:
  340. return
  341. self.__setup_pid = 0
  342. self.__setup_pid = os.spawnl(os.P_NOWAIT, self.__setup_cmd, "ibus-setup")
  343. gobject.type_register(Panel, "IBusPanel")