from .. import bar, manager, xcbq, window
import base

import xcb
from xcb.xproto import EventMask, SetMode
import atexit
import struct


class Icon(window._Window):
    _windowMask = EventMask.StructureNotify |\
                  EventMask.Exposure

    def __init__(self, win, qtile, systray):
        window._Window.__init__(self, win, qtile)
        self.systray = systray

    def _configure_icon(self, pos):
        window.configure(
            x=self.offset + (self.icon_size * pos),
            y=0, width=self.icon_size,
            height=self.icon_size)

    def handle_ConfigureNotify(self, event):
        self.systray.draw()
        return False

    def handle_DestroyNotify(self, event):
        wid = event.window
        del(self.qtile.windowMap[wid])
        del(self.systray.icons[wid])
        self.systray.draw()
        return False

    handle_UnmapNotify = handle_DestroyNotify


class TrayWindow(window._Window):
    _windowMask = EventMask.StructureNotify |\
                  EventMask.Exposure

    def __init__(self, win, qtile, systray):
        window._Window.__init__(self, win, qtile)
        self.systray = systray

    def handle_ClientMessage(self, event):
        atoms = self.qtile.conn.atoms

        opcode = xcb.xproto.ClientMessageData(event, 0, 20).data32[2]
        data = xcb.xproto.ClientMessageData(event, 12, 20)
        task = data.data32[2]

        conn = self.qtile.conn.conn
        parent = self.systray.bar.window.window

        if opcode == atoms['_NET_SYSTEM_TRAY_OPCODE']:
            try:
                w = xcbq.Window(self.qtile.conn, task)
                icon = Icon(w, self.qtile, self.systray)
                self.systray.icons[task] = icon
                self.qtile.windowMap[task] = icon

                # add icon window to the save-set, so it gets reparented
                # to the root window when qtile dies
                conn.core.ChangeSaveSet(SetMode.Insert, task)

                conn.core.ReparentWindow(task, parent.wid, 0, 0)
                conn.flush()
                w.map()
            except xcb.xproto.DrawableError:
                # The icon wasn't ready to be drawn yet... (NetworkManager does
                # this sometimes), so we just forget about it and wait for the
                # next event.
                pass
        return False


class Systray(base._Widget):
    """
        A widget that manage system tray
    """
    defaults = manager.Defaults(
                ('icon_size', 20, 'Icon width'),
                ('padding', 5, 'Padding between icons'),
                ('background', None, 'Background colour'),
            )

    def __init__(self, **config):
        base._Widget.__init__(self, bar.CALCULATED, **config)
        self.traywin = None
        self.icons = {}

    def click(self, x, y, button):
        pass

    def calculate_width(self):
        width = len(self.icons) * (
            self.icon_size + self.padding) + self.padding
        return width

    def _configure(self, qtile, bar):
        base._Widget._configure(self, qtile, bar)
        self.qtile = qtile
        self.bar = bar
        atoms = qtile.conn.atoms
        win = qtile.conn.create_window(-1, -1, 1, 1)
        self.traywin = TrayWindow(win, self.qtile, self)
        qtile.windowMap[win.wid] = self.traywin
        qtile.conn.conn.core.SetSelectionOwner(
            win.wid,
            atoms['_NET_SYSTEM_TRAY_S0'],
            xcb.CurrentTime
        )
        event = struct.pack('BBHII5I', 33, 32, 0, qtile.root.wid,
                            atoms['MANAGER'],
                            xcb.CurrentTime, atoms['_NET_SYSTEM_TRAY_S0'],
                            win.wid, 0, 0)
        qtile.root.send_event(event, mask=EventMask.StructureNotify)

        # cleanup before exit
        atexit.register(self.cleanup)

    def draw(self):
        self.drawer.clear(self.background or self.bar.background)
        self.drawer.draw(self.offset, self.calculate_width())
        for pos, icon in enumerate(self.icons.values()):
            icon.place(
                    self.offset + (
                        self.icon_size + self.padding) * pos + self.padding,
                    self.bar.height / 2 - self.icon_size / 2,
                    self.icon_size, self.icon_size,
                    0,
                    None
            )

    def cleanup(self):
        atoms = self.qtile.conn.atoms
        self.qtile.conn.conn.core.SetSelectionOwner(
            0,
            atoms['_NET_SYSTEM_TRAY_S0'],
            xcb.CurrentTime,
        )
        self.traywin.hide()

@@ -361,32 +361,85 @@
 ystray = systray
+%0A        self.width = self.height = systray.icon_size
 %0A%0A    def _confi
@@ -432,26 +432,32 @@
     def 
-_c
+handle_C
 onfigure
 _icon(se
@@ -452,23 +452,26 @@
 gure
-_icon
+Notify
 (self, 
-pos
+event
 ):%0A 
@@ -481,106 +481,298 @@
     
-window.configure(%0A            x=self.offset + (self.icon_size * pos),%0A            y=0, width=self.
+icon_size = self.systray.icon_size%0A        self.updateHints()%0A%0A        try:%0A            width, height = self.hints%5B%22min_width%22%5D, self.hints%5B%22min_height%22%5D%0A        except KeyError:%0A            width, height = icon_size%0A%0A        if height %3E icon_size:%0A            new_width = width / height * 
 icon
@@ -768,33 +768,32 @@
 ight * icon_size
-,
 %0A            hei
@@ -799,14 +799,11 @@
 ight
-=self.
+ = 
 icon
@@ -811,55 +811,86 @@
 size
-)%0A
 %0A    
-def handle_ConfigureNotify(self, event):
+        width = new_width%0A        self.width, self.height = width, height
 %0A   
@@ -3169,56 +3169,68 @@
 h = 
-len(self.icons) * (%0A            self.icon_size
+sum(%5Bi.width for i in self.icons.values()%5D)%0A        width
  +
+=
  sel
@@ -3242,24 +3242,26 @@
 ding
-) + self.padding
+ * len(self.icons)
 %0A   
@@ -4274,16 +4274,47 @@
 idth())%0A
+        xoffset = self.padding%0A
         
@@ -4424,85 +4424,15 @@
 t + 
-(%0A                        self.icon_size + self.padding) * pos + self.padding
+xoffset
 ,%0A  
@@ -4511,30 +4511,26 @@
         
-self.icon_size
+icon.width
 , self.i
@@ -4592,32 +4592,81 @@
 ne%0A            )
+%0A            xoffset += icon.width + self.padding
 %0A%0A    def cleanu

use normal hints to get systray clients size