# Copyright 2012 Florian Mounier
# Copyright 2014 Sean Vig
# Copyright 2014 Tycho Andersen
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""
    This is mostly stolen from qtile's tests/scripts/window.py
"""
from __future__ import print_function
import os
import sys
import struct
import time
import xcffib
import xcffib.xproto
from xcffib.xproto import EventMask
from xcffib.testing import XvfbTest

class TestWindow(XvfbTest):

    def test_the_script(self):
        NAME = "one"
        for i in range(20):
            try:
                conn = xcffib.connect(os.environ['DISPLAY'])
            except xcffib.ConnectionException:
                time.sleep(0.1)
                continue
            except Exception as v:
                print("Error opening test window: ", type(v), v, file=sys.stderr)
                sys.exit(1)
            break
        else:
            print("Could not open window on display %s" % (sys.argv[1]), file=sys.stderr)
            sys.exit(1)

        screen = conn.get_setup().roots[conn.pref_screen]

        window = conn.generate_id()
        background = conn.core.AllocColor(screen.default_colormap, 0x2828, 0x8383, 0xCECE).reply().pixel # Color "#2883ce"
        conn.core.CreateWindow(xcffib.CopyFromParent, window, screen.root,
                100, 100, 100, 100, 1,
                xcffib.xproto.WindowClass.InputOutput, screen.root_visual,
                xcffib.xproto.CW.BackPixel | xcffib.xproto.CW.EventMask,
                [background, xcffib.xproto.EventMask.StructureNotify | xcffib.xproto.EventMask.Exposure])

        conn.core.ChangeProperty(xcffib.xproto.PropMode.Replace,
                window, xcffib.xproto.Atom.WM_NAME,
                xcffib.xproto.Atom.STRING, 8, len(NAME),
                NAME)

        wm_protocols = "WM_PROTOCOLS"
        wm_protocols = conn.core.InternAtom(0, len(wm_protocols), wm_protocols).reply().atom

        wm_delete_window = "WM_DELETE_WINDOW"
        wm_delete_window = conn.core.InternAtom(0, len(wm_delete_window), wm_delete_window).reply().atom

        conn.core.ChangeProperty(xcffib.xproto.PropMode.Replace,
                window, wm_protocols,
                xcffib.xproto.Atom.ATOM, 32, 1,
                [wm_delete_window])

        conn.core.ConfigureWindow(window,
                xcffib.xproto.ConfigWindow.X | xcffib.xproto.ConfigWindow.Y |
                xcffib.xproto.ConfigWindow.Width | xcffib.xproto.ConfigWindow.Height |
                xcffib.xproto.ConfigWindow.BorderWidth,
                [0, 0, 100, 100, 1])
        conn.core.MapWindow(window)
        conn.flush()
        conn.core.ConfigureWindow(window,
                xcffib.xproto.ConfigWindow.X | xcffib.xproto.ConfigWindow.Y |
                xcffib.xproto.ConfigWindow.Width | xcffib.xproto.ConfigWindow.Height |
                xcffib.xproto.ConfigWindow.BorderWidth,
                [0, 0, 100, 100, 1])

        # now kill the window from the "wm" side via WM_DELETE_WINDOW protocol
        WM_PROTOCOLS = self.conn.core.InternAtom(False, len("WM_PROTOCOLS"), "WM_PROTOCOLS").reply().atom
        WM_DELETE_WINDOW = self.conn.core.InternAtom(False, len("WM_DELETE_WINDOW"), "WM_DELETE_WINDOW").reply().atom
        vals = [
            33,  # ClientMessageEvent
            32,  # Format
            0,
            window,
            WM_PROTOCOLS,
            WM_DELETE_WINDOW,
            xcffib.xproto.Time.CurrentTime,
            0,
            0,
            0,
        ]
        e = struct.pack('BBHII5I', *vals)
        self.conn.core.SendEvent(False, window, EventMask.NoEvent, e)

        self.conn.flush()

        while 1:
            conn.flush()
            event = conn.wait_for_event()
            if event.__class__ == xcffib.xproto.ClientMessageEvent:
                atom = conn.core.GetAtomName(event.type).reply().name.to_string()
                print(atom)
                if atom == "WM_PROTOCOLS":
                    break
        # This test passes if it gets all the way here without dying :-)
