#!/usr/bin/env python
# vim:set et sts=4 sw=4:
#
# ibus - The Input Bus
#
# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA  02111-1307  USA

import os
import os.path
import atexit
import sys
import time
import ibus
import dbus
import signal

daemon = "/usr/bin/ibus-daemon"
x11 = "/usr/bin/ibus-x11"
ui = "/usr/bin/ibus-ui-gtk"
conf = "/usr/bin/ibus-gconf"

class Launcher(object):
    def __init__(self):
        super(Launcher, self).__init__()
        self.__daemon_pid = 0
        self.__ui_pid = 0
        self.__conf_pid = 0
        self.__x11_pid = 0
        self.__bus = None
        self.__preload_engine_completed = False

    def __start_process(self, path, args, cmd):
        pid = 0
        try:
            print "Starting %s" % cmd,
            pid = os.spawnv (os.P_NOWAIT, path, args)
            print "OK"
        except:
            print >> sys.stderr, "Start %s Failed" % cmd
        return pid

    def __bus_destroy_cb(self, bus):
        self.__bus = None
        ibus.main_quit()

    def __bus_config_reloaded_cb(self, bus):
        self.__launch_auto_load_engines()

    def __signal_cb(self, sig, stack):
        if sig == signal.SIGCHLD:
            pid, status = os.wait()
            if pid == self.__daemon_pid:
                self.__daemon_pid = 0
                self.__bus = None
            elif pid == self.__x11_pid:
                self.__x11_pid = 0
            elif pid == self.__ui_pid:
                self.__ui_pid = 0
            elif pid == self.__conf_pid:
                self.__conf_pid = 0
        elif sig == signal.SIGTERM or sig == signal.SIGINT:
            sys.exit(1)

    def __atexit_cb(self):
        if self.__bus:
            try:
                self.__bus.kill()
            except:
                pass
        os.kill(-os.getpid(), signal.SIGTERM)

    def run(self):
        try:
            bus = ibus.Bus()
            print >> sys.stderr, "Found an ibus-daemon has been started!"
            sys.exit(1)
        except dbus.DBusException, e:
            pass

        # make self process group leader
        if os.getpid() != os.getpgid(os.getpid()):
            os.setpgid(0, 0)

        signal.signal(signal.SIGCHLD, self.__signal_cb)
        signal.signal(signal.SIGINT, self.__signal_cb)
        signal.signal(signal.SIGTERM, self.__signal_cb)
        atexit.register(self.__atexit_cb)

        # start ibus-daemon
        self.__daemon_pid = self.__start_process(daemon, [daemon], "ibus-daemon")
        if self.__daemon_pid <= 0:
            sys.exit(1)

        for i in range(5):
            time.sleep (1)
            try:
                self.__bus = ibus.Bus()
                break
            except:
                pass

        if self.__bus == None:
            print >> sys.stderr, "Start ibus-daemon failed"
            sys.exit(1)

        self.__bus.connect("destroy", self.__bus_destroy_cb)
        self.__bus.connect("config-reloaded", self.__bus_config_reloaded_cb)

        self.__conf_pid = self.__start_process(conf, [conf], "ibus-conf")
        self.__ui_pid = self.__start_process(ui, [ui], "ibus-ui-gtk")
        self.__x11_pid = self.__start_process(x11, [x11, "--kill-daemon"], "ibus-x11")
        ibus.main()

    def __launch_auto_load_engines(self):
        if self.__preload_engine_completed:
            return
        engines = []
        try:
            engines = self.__bus.config_get_value("general", "preload_engines", None)
            if not engines:
                engines = []
            else:
                self.__preload_engine_completed = True
        except:
            pass
        for e in engines:
            try:
                lang, name = e.split(":")
                self.__bus.register_start_engine(lang, name)
            except:
                import traceback
                traceback.print_exc()



if __name__ == "__main__":
    Launcher().run()
