def __on_accel_show_hide(self, *args):
        # Cancel pending timers.
        if self.expose_animation:
            self.expose_animation.stop()
            self.expose_animation = None

        duration = 0
        if self.settings.get_window_animations():
            duration = 30

        if not self.get_visible():
            self.show()
            rect = self.__calculate_window_size()
            self.expose_animation = Animation(duration, self.expose_step, 1.0)
        else:
            rect = self.get_position() + self.get_size()
            self.expose_animation = Animation(duration, self.expose_step, 0.0)
            self.expose_animation.set_complete_callback(self.hide)
        self.expose_animation.set_interpolator(Animation.QuadraticEaseInOutInterpolator)
        self.expose_animation.set_update_callback(self.__expose_animation_callback, *rect)
        self.expose_animation.start()
        return True
class XfConWindow(gtk.Window):
    def __init__(self):
        super(XfConWindow, self).__init__()

        XfConDialog.init(self)

        self.settings = XfConSettings.Instance()

        self.activate()
        self.set_decorated(False)
        self.set_gravity(gtk.gdk.GRAVITY_STATIC)
        self.set_skip_pager_hint(True)
        self.set_skip_taskbar_hint(True)
        self.set_title(APPNAME)
        self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_UTILITY)
        self.set_keep_above(True)
        self.set_urgency_hint(True)
        self.set_resizable(False)
        self.set_position(gtk.WIN_POS_NONE)
        self.add_accel_group(XfConKeyBinder.create())

        self.notebook = XfConNotebook()
        self.notebook.connect(XfConObject.XFCON_SIGNAL_MENU_BUILD, self.__on_menu_build)
        self.notebook.connect(XfConObject.XFCON_SIGNAL_MENU_SHOW, self.__on_menu_show)
        self.notebook.connect(XfConObject.XFCON_SIGNAL_MENU_HIDE, self.__on_menu_hide)
        self.add(self.notebook)

        # trayicon!
        # TODO(error): make a nice definition out of this.
        # Can't see the tray icon on awesome. why's that?
        img = pixmapfile("terminal.png")
        self.tray_icon = gtk.status_icon_new_from_file(img)
        self.tray_icon.set_tooltip(APPNAME)
        self.tray_icon.set_visible(True)
        self.tray_icon.connect("popup-menu", self.__on_accel_show_hide)
        self.tray_icon.connect("activate", self.__on_accel_show_hide)

        self.connect("delete-event", self.__on_destroy)
        self.connect("set-focus", self.__on_focus_move)

        self.last_focus = None
        self.expose_animation = None
        self.expose_step = 0.0

        self.__import_plugins()
        self.__bind_config()
        self.__bind_keys()
        self.__apply_config()
        self.__show_start_notification()

    def __show_start_notification(self):
        # Pop-up that shows that XfCon is working properly (if not
        # unset in the preferences windows)
        filename = pixmapfile("exclam.png")
        label = self.settings.get_property("key-show-hide")
        notification = pynotify.Notification(
            APPNAME, _("XfCon is now running,\n" "press <b>%s</b> to use it.") % label, filename
        )
        notification.show()

    def __import_plugins(self):
        self.module_names = [
            filename for filename in os.listdir(PLUGINS_DIR) if os.path.isdir(PLUGINS_DIR + "/" + filename)
        ]
        self.plugins = {}
        for module_name in self.module_names:
            module = __import__("plugins." + module_name + ".plugin", fromlist=["Plugin"])
            plugin = module.Plugin(self)
            self.plugins[module_name] = plugin
            if plugin.is_default():
                # TODO(ender) fix this.
                self.default_plugin = plugin

    def __bind_config(self):
        self.settings.connect("notify::window-height", self.__config_set_window_size)
        self.settings.connect("notify::window-width", self.__config_set_window_size)
        self.notebook.connect(XfConNotebook.XFCON_SIGNAL_BUILD_DEFAULT_VIEW, self.__on_tab_add)

    def __bind_keys(self):
        XfConKeyBinder.register(
            self,
            [
                (self.settings.get_property("key-quit"), self.__on_accel_quit),
                (self.settings.get_property("key-new-tab"), self.__on_accel_tab_create),
            ],
        )

        XfConKeyBinder.register_global(
            "XfCon Global", [(self.settings.get_property("key-show-hide"), self.__on_accel_show_hide)]
        )

    def __apply_config(self):
        self.__config_set_window_size()

    def __set_window_size(self, x, y, w, h):
        self.set_geometry_hints(self, min_width=w, min_height=h, max_width=w, max_height=h, base_width=w, base_height=h)
        self.move(x, y)

    def __config_set_window_size(self, *ignore):
        self.__set_window_size(*self.__calculate_window_size())

    def __on_tab_add(self, *ignore):
        return self.__do_create_default_view()

    def __on_destroy(self, *args):
        self.hide()
        return True

    def __on_focus_move(self, window, widget):
        self.last_focus = widget

    def __on_about_show(self, *args):
        # TODO(error) implement.
        for plugin in self.plugins.values():
            view = plugin.on_about_create()
            # TODO(error) ATTACH!
        XfConDialog.about()

    def __on_menu_build(self, source, menu):
        """
    Constructs user menu.
    """
        separator = gtk.SeparatorMenuItem()
        separator.show()
        menu.add(separator)
        for plugin in self.plugins.values():
            plugin.on_menu_build(menu)
        separator = gtk.SeparatorMenuItem()
        separator.show()
        menu.add(separator)

        item = gtk.ImageMenuItem(gtk.STOCK_CLOSE, True)
        item.set_label(_("Close Tab"))
        item.show()
        item.connect("activate", self.__on_accel_tab_delete)
        menu.add(item)

        item = gtk.ImageMenuItem(gtk.STOCK_ABOUT, True)
        item.set_label(_("About"))
        item.show()
        item.connect("activate", self.__on_about_show)
        menu.add(item)

        item = gtk.ImageMenuItem(gtk.STOCK_QUIT, True)
        item.set_label(_("Quit"))
        item.show()
        item.connect("activate", self.__on_accel_quit)
        menu.add(item)

    def __on_menu_show(self, *args):
        for plugin in self.plugins.values():
            plugin.on_menu_show()

    def __on_menu_hide(self, *args):
        for plugin in self.plugins.values():
            plugin.on_menu_hide()

    def __calculate_window_size(self):
        screen = self.get_screen()
        height = self.settings.get_property("window-height")
        width = self.settings.get_property("window-width")
        if self.settings.get_window_follows_mouse():
            root = display.Display().screen().root.query_pointer()._data
            root_x = root["root_x"]
            root_y = root["root_y"]
            rect = screen.get_monitor_geometry(screen.get_monitor_at_point(root_x, root_y))
        else:
            rect = screen.get_monitor_geometry(screen.get_primary_monitor())
        rect.height = rect.height * height / 100
        width = rect.width * width / 100
        rect.x = rect.x + (rect.width - width) / 2
        rect.width = width
        return (rect.x, rect.y, rect.width, rect.height)

    def __on_accel_show_hide(self, *args):
        # Cancel pending timers.
        if self.expose_animation:
            self.expose_animation.stop()
            self.expose_animation = None

        duration = 0
        if self.settings.get_window_animations():
            duration = 30

        if not self.get_visible():
            self.show()
            rect = self.__calculate_window_size()
            self.expose_animation = Animation(duration, self.expose_step, 1.0)
        else:
            rect = self.get_position() + self.get_size()
            self.expose_animation = Animation(duration, self.expose_step, 0.0)
            self.expose_animation.set_complete_callback(self.hide)
        self.expose_animation.set_interpolator(Animation.QuadraticEaseInOutInterpolator)
        self.expose_animation.set_update_callback(self.__expose_animation_callback, *rect)
        self.expose_animation.start()
        return True

    def __expose_animation_callback(self, value, x, y, w, h):
        type = self.settings.get_window_animation_expose_direction()
        self.expose_step = value
        if type == gtk.DIR_UP:
            y -= int((1.0 - value) * h)
        elif type == gtk.DIR_LEFT:
            x -= int((1.0 - value) * w)
        elif type == gtk.DIR_DOWN:
            y += int((1.0 - value) * gtk.gdk.screen_get_default().get_height())
        else:
            x += int((1.0 - value) * gtk.gdk.screen_get_default().get_width())
        self.__set_window_size(x, y, w, h)
        if self.settings.get_window_animation_expose_alpha():
            self.set_opacity(value)

    def __on_accel_quit(self, *args):
        wants_quit = XfConDialog.question_yes_no(_("Are you sure to quit?"), _("All running processes will be killed."))
        if wants_quit:
            gtk.main_quit()
        return True

    def __on_accel_tab_create(self, *args):
        self.create_tab()
        return True

    def __on_accel_tab_delete(self, *args):
        self.delete_tab()
        return True

    def __do_create_default_view(self, directory=None, command=None):
        default_box = self.default_plugin.on_view_create()
        return default_box

    ###############################################################################

    def create_tab(self, child=None):
        container = child or self.__do_create_default_view()
        index = self.notebook.append_page(container)
        self.notebook.set_current_page(index)

    def delete_tab(self, pagepos=-1):
        if pagepos == -1:
            pagepos = self.notebook.get_current_page()

        child = self.notebook.get_nth_page(pagepos)
        self.notebook.remove_page(pagepos)
        child.destroy()

    def save_focus(self):
        self.last_focus = self.get_focus()

    def restore_focus(self):
        self.set_focus(self.last_focus)

    def show(self):
        # setting window in all desktops
        self.stick()

        for plugin in self.plugins.values():
            plugin.on_show()

        # if we reposition window before showing it, it will be again repositioned
        # to respect panels position once shown. we don't want this, although it would
        # be nice to expose panels later
        # http://stackoverflow.com/questions/502282
        self.show_all()
        self.restore_focus()

    def hide(self):
        self.save_focus()
        for plugin in self.plugins.values():
            plugin.on_hide()
        super(self.__class__, self).hide()