from config import settings
from utils import wallpaper
from utils.BGWatcher import BGWatcher
from utils.tiling import Tiling

try:
    from utils import ewmh
except ImportError:
    log("Couldn't load EWMH support. Some window flags won't work.")
    ewmh = Null

import gobject
import gtk

_BGWATCHER = BGWatcher()

_MOOSE_DELAY = 100


# this gives us support for real transparency when using a composition manager
_TRANSLUCENT_CMAP = None
if (not HAVE_WIN32):
    # get the ARGB visual for an alpha channel
    visual = gtk.gdk.visual_get_best_with_depth(32)
    if (visual):
        _TRANSLUCENT_CMAP = gtk.gdk.Colormap(visual, True)


#
# Class for transparent windows.
#
class GlassWindow(gtk.Window):

    #
    # Constructor.
    #
    def __init__(self, wintype = gtk.WINDOW_TOPLEVEL):

        # handler for transparency updates
        self.__update_handler = None

        # remember the current window position to detect movements
        self.__position = (0, 0)
        self.__size = (0, 0)


        # push the tranlucent colormap for creating the window and pop it
        # afterwards to not mess up other windows
        if (settings.translucent and _TRANSLUCENT_CMAP):
            gtk.widget_push_colormap(_TRANSLUCENT_CMAP)
        gtk.Window.__init__(self, wintype)
        if (settings.translucent and _TRANSLUCENT_CMAP):
            gtk.widget_pop_colormap()


        self.__layout = gtk.Fixed()
        self.__layout.show()
        gtk.Window.add(self, self.__layout)



        # welcome to the future!
        if (not settings.translucent and not HAVE_WIN32):
            # mommy, my xserver doesn't have translucency... :(
            self.__background = Tiling()
            self.__background.show()
            self.__layout.put(self.__background, 0, 0)
            
            self.connect("configure-event", self.__on_configure)

            _BGWATCHER.add_observer(self.__bg_observer)


        else:
            # real men don't need wimpy pseudo-transparency... 8)
            self.modify_bg(gtk.STATE_NORMAL,
                           gtk.gdk.color_parse("#000000"))

            if (HAVE_WIN32):
                import win32gui
                import winxpgui
                LWA_COLORKEY = 0x01
                LWA_ALPHA = 0x02
                WS_EX_LAYERED = 0x80000
                GWL_EXSTYLE = -20

                self.realize()
                style = win32gui.GetWindowLong(self.window.handle, GWL_EXSTYLE)
                style |= WS_EX_LAYERED
                win32gui.SetWindowLong(self.window.handle, GWL_EXSTYLE, style)
                winxpgui.SetLayeredWindowAttributes(self.window.handle,
                                                    0x0a0a0a, 0xff,
                                                    LWA_COLORKEY)

    #
    # Override add method.
    #
    def add(self, widget):

        self.__layout.put(widget, 0, 0)


    #
    # Override resize method.
    #
    def resize(self, width, height):

        self.__layout.set_size_request(width, height)            
        gobject.idle_add(gtk.Window.resize, self, width, height)



    #
    # Observer method for the background.
    # Connect this method to the BG watcher.
    #
    def __bg_observer(self, src, cmd):

        self.__update_bg()



    #
    # Updates the background for transparency.
    #
    def __update_bg(self):
        
        if (self.__update_handler):
            gobject.source_remove(self.__update_handler)
            self.__update_handler = gobject.timeout_add(_MOOSE_DELAY,
                                                        self.__updater)
        else: self.__updater()



    def __updater(self):

        if (not self.window): return

        x, y = self.window.get_origin()
        width, height = self.window.get_size()
        if (width > 1 and height > 1):
            self.__capture_bg(x, y, width, height)



    #
    # Captures the background to create transparency.
    #
    def __capture_bg(self, x, y, width, height):

        wallpaper.get_wallpaper(self.__background, x, y, width, height)
        self.queue_draw()



    #
    # Reacts on moving the window.
    #
    def __on_configure(self, src, event):

        pos = self.window.get_origin()
        size = self.window.get_size()
        if (pos != self.__position or size != self.__size):
            self.__position = pos
            self.__size = size
            self.__update_bg()



    #
    # Sets the BELOW window flag.
    #
    def _set_flag_below(self, value):

        if (not self.__get_window_manager() in ["Enlightenment"] and
            not self.get_property("visible")):
            gobject.timeout_add(500, self._set_flag_below, value)

        elif (self.window):
            ewmh.set_above(self.window, not value)
            ewmh.set_below(self.window, value)



    #
    # Sets the ABOVE window flag.
    #
    def _set_flag_above(self, value):

        if (not self.__get_window_manager() in ["Enlightenment"] and
            not self.__get_window_manager().startswith("Xfwm4") and
            not self.get_property("visible")):
            gobject.timeout_add(500, self._set_flag_above, value)

        elif (self.window):
            ewmh.set_below(self.window, not value)
            ewmh.set_above(self.window, value)



    #
    # Sets the STICKY window flag.
    #
    def _set_flag_sticky(self, value):

        if (value): self.stick()
        else: self.unstick()



    def _set_type_hint_dock(self, window, value):

        ewmh.set_type_dock(window, value)

        #value and window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK) or \
        #          window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_NORMAL)



    #
    # Sets the MANAGED window flag.
    #
    def _set_flag_managed(self, value):

        if (value):
            self.set_property("skip-taskbar-hint", 0)
            self.set_property("skip-pager-hint", 0)
            self._set_type_hint_dock(self.window, False)
        else:
            self.set_property("skip-taskbar-hint", 1)
            self.set_property("skip-pager-hint", 1)
            wm = self.__get_window_manager()
            if (wm == "Metacity"): self._set_type_hint_dock(self.window, True)



    #
    # Sets the DECORATED window flag.
    #
    def _set_flag_decorated(self, value):

        if (value): self.set_decorated(True)
        else: self.set_decorated(False)



    #
    # Returns the name of the running EWMH compliant window manager or "".
    #
    def __get_window_manager(self):

        if (HAVE_WIN32): return "Windows"

        name = ""
        win = _WM_NAME_WIN
        if (win != None):
            try:
                name = win.property_get("_NET_WM_NAME")[2]
            except TypeError, exc:
                log("Your window manager doesn't support _NET_WM_NAME!\n"
                    "Switch to a EWMH compliant WM.\n"
                    "The following error occured:\n%s" % (exc,))
                return name

        return name



if (not HAVE_WIN32):
    # get the window where the EMWH compliant window manager tells its name
    root = gtk.gdk.get_default_root_window()

    try:
        ident = root.property_get("_NET_SUPPORTING_WM_CHECK", "WINDOW")[2]
        _WM_NAME_WIN = gtk.gdk.window_foreign_new(long(ident[0]))
    except TypeError, exc:
        _WM_NAME_WIN = ""
        log("Your window manager doesn't support "
            "_NET_SUPPORTING_WM_CHECK! Switch to a compliant WM!"
            "The following error occured:\n%s" % (exc,))

