#include "Border.h"
#include "Client.h"
#include "Manager.h"

GC Border::m_drawGC;
unsigned long Border::m_frameBackgroundPixel = 0;
unsigned long Border::m_buttonBackgroundPixel;
unsigned long Border::m_borderPixel;

declareList(RectangleList, XRectangle);
implementList(RectangleList, XRectangle);

class BorderRectangleList : public RectangleList {
public:
BorderRectangleList() { }
    ~BorderRectangleList() { }

    void appendRect(int x, int y, int w, int h);
};

void BorderRectangleList::appendRect(int x, int y, int w, int h) {
    XRectangle r;
    r.x = x;
    r.y = y;
    r.width = w;
    r.height = h;
    append(r);
}

Border::Border(Client *const c, Window child) : m_client(c), m_parent(0), m_tab(0), m_child(child), m_hideButton(0), m_closeButton(0), m_label(0), m_hideButtonGtk(0), m_closeButtonGtk(0), m_tabGtk(0), m_labelGtk(0), m_gdkwindow(0) {
    m_parent = root();
    if (m_frameBackgroundPixel == 0) {
        m_frameBackgroundPixel = windowManager()->allocateColour(frame_bg, "frame background");
        m_buttonBackgroundPixel = windowManager()->allocateColour(button_bg, "button background");
        m_borderPixel = windowManager()->allocateColour(border_fg, "border");
        m_drawGC = DefaultGC(display(), DefaultScreen(display()));
    }
}


Border::~Border() {
    if (m_parent != root()) {
        if (!m_parent) fprintf(stderr,"wmG: zero parent in Border::~Border\n");
        else {
            XDestroyWindow(display(), m_tab);
            gtk_widget_destroy(m_labelGtk);
            gtk_widget_destroy(m_tabGtk);
            XDestroyWindow(display(), m_hideButton);
//            gtk_widget_destroy(m_hideButtonGtk);
            XDestroyWindow(display(), m_closeButton);
//            gtk_widget_destroy(m_closeButtonGtk);
            XDestroyWindow(display(), m_parent);
        }
    }
}


void Border::fatal(char *s) {
    windowManager()->fatal(s);
}


Display *Border::display() {
    return m_client->display();
}


WindowManager *Border::windowManager() {
    return m_client->windowManager();
}


Window Border::root() {
    return m_client->root();
}


void Border::expose(XExposeEvent *e) {
    if (e->window != m_tab) return;
    drawLabel();
}


void Border::drawLabel() {
    m_label = m_client->m_label;
    if (m_label) {
        gtk_label_set_text(GTK_LABEL(m_labelGtk), m_label);
//	gtk_widget_draw_default(m_labelGtk);
    }
}


Boolean Border::isTransient(void) {
    return m_client->isTransient();
}


Boolean Border::isFixedSize(void) {
    return m_client->isFixedSize();
}

void Border::shapeParent(int w, int h) {
    XRectangle r;
    r.x = 0;
    r.y = 0;
    r.width = w + frame_size * 2;
    r.height = h + 20 + frame_size * 2;
    XShapeCombineRectangles(display(), m_parent, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
    r.x = xIndent();
    r.y = yIndent();
    r.width = w;
    r.height = h;
    XShapeCombineRectangles(display(), m_parent, ShapeClip, 0, 0, &r, 1, ShapeSet, YXBanded);
}


void Border::shapeTab(int w, int) {
    XRectangle r;
    r.x = 0;
    r.y = 0;
    r.width = w;
    r.height = title_size;
    XShapeCombineRectangles(display(), m_tab, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
    r.x = 1;
    r.y = 1;
    r.width = w - 2;
    r.height = title_size - 2;
    XShapeCombineRectangles(display(), m_tab, ShapeClip, 0, 0, &r, 1, ShapeSet, YXBanded);
    r.x = r.y = 0;
    r.width = r.height = title_size - 4;
    XShapeCombineRectangles(display(), m_hideButton, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
    r.x = r.y = 1;
    r.width = r.height = title_size - 6;
    XShapeCombineRectangles(display(), m_hideButton, ShapeClip, 0, 0, &r, 1, ShapeSet, YXBanded);
    r.x = r.y = 0;
    r.width = r.height = title_size - 4;
    XShapeCombineRectangles(display(), m_closeButton, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
    r.x = r.y = 1;
    r.width = r.height = title_size - 6;
    XShapeCombineRectangles(display(), m_closeButton, ShapeClip, 0, 0, &r, 1, ShapeSet, YXBanded);
}

void Border::configure(int x, int y, int w, int h, unsigned long mask, int detail, Boolean active, Boolean onlyActivate) {
    if(!m_parent || m_parent == root()) {
        m_parent = XCreateSimpleWindow(display(), root(), 1, 1, 1, 1, 0, m_borderPixel, m_frameBackgroundPixel);
//        m_tab = XCreateSimpleWindow(display(), m_parent, 1, 1, 1, 1, 0, m_borderPixel, m_frameBackgroundPixel);
        m_tabGtk = gtk_plug_new(m_parent);
//	gtk_window_set_policy(GTK_WINDOW(m_tabGtk), true, true, false);
        gtk_widget_show(m_tabGtk);
        m_labelGtk = gtk_label_new(m_label);
        gtk_widget_show(m_labelGtk);
        gtk_container_add(GTK_CONTAINER(m_tabGtk), m_labelGtk);
        m_hideButton = XCreateSimpleWindow(display(), m_parent, 1, 1, 1, 1, 0, m_borderPixel, m_buttonBackgroundPixel);
//        m_hideButtonGtk = gtk_window_new(GTK_WINDOW_TOPLEVEL);
//        gtk_widget_show(m_hideButtonGtk);
        m_closeButton = XCreateSimpleWindow(display(), m_parent, 1, 1, 1, 1, 0, m_borderPixel, m_buttonBackgroundPixel);
//        m_closeButtonGtk = gtk_window_new(GTK_WINDOW_TOPLEVEL);
//        gtk_widget_show(m_closeButtonGtk);
        m_tab = GTK_XWINDOW(m_tabGtk);
        XReparentWindow(display(), m_tab, m_parent, frame_size, frame_size);
    }
    shapeTab(w, h);
    drawLabel();
    XMapWindow(display(), m_tab);
    XSelectInput(display(), m_parent, SubstructureRedirectMask | SubstructureNotifyMask | ButtonPressMask | ButtonReleaseMask);
    XSelectInput(display(), m_tab, ExposureMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask);
    XSelectInput(display(), m_hideButton, ButtonPressMask | ButtonReleaseMask);
    XSelectInput(display(), m_closeButton, ButtonPressMask | ButtonReleaseMask);
    gtk_widget_set_state(m_labelGtk, (active == True ? GTK_STATE_SELECTED : GTK_STATE_NORMAL));
    gtk_widget_set_state(m_tabGtk, (active == True ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL));
    mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
    gtk_widget_set_usize(m_labelGtk, w - 2, title_size - 2);
    gtk_widget_set_usize(m_tabGtk, w - 2, title_size - 2);
//    gtk_widget_set_usize(m_hideButtonGtk, title_size - 4, title_size - 4);
//    gtk_widget_set_usize(m_closeButtonGtk, title_size - 4, title_size - 4);
    XWindowChanges wc;
    wc.x = x - (m_client->m_hasBorder ? xIndent() : 0);
    wc.y = y - (m_client->m_hasBorder ? yIndent() : (yIndent() - frame_size));
    wc.width  = w + (m_client->m_hasBorder ? frame_size * 2 : 0);
    wc.height = h + (m_client->m_hasBorder ? (yIndent() + frame_size) : (yIndent() - frame_size));
    wc.border_width = 0;
    wc.sibling = None;
    wc.stack_mode = detail;
    XConfigureWindow(display(), m_parent, mask, &wc);
    unsigned long rmask = 0L;
    if (mask & CWWidth)  rmask |= CWX;
    if (mask & CWHeight) rmask |= CWY;
    wc.x = frame_size;
    wc.y = frame_size;
    wc.height = title_size;
    wc.width = w;
    XConfigureWindow(display(), m_tab, mask, &wc);
    shapeTab(w, h);
    wc.x = w - (title_size - 4);
    wc.y = frame_size + 2;
    wc.width = wc.height = title_size - 4;
    XConfigureWindow(display(), m_closeButton, mask, &wc);
    wc.x = w - ((title_size - 4) * 2) - 1;
    wc.y = frame_size + 2;
    wc.width = wc.height = title_size - 4;
    XConfigureWindow(display(), m_hideButton, mask, &wc);
    if(m_gdkwindow != 0)
        gtk_widget_set_parent_window(m_tabGtk, m_gdkwindow);
//    reparent();
    XMoveResizeWindow(display(), m_client->m_window, xIndent(), yIndent(), m_client->m_w, m_client->m_h);
//    gtk_widget_draw_default(m_labelGtk);
    if(m_gdkwindow != 0)
        m_gdkwindow = gdk_window_foreign_new(m_tab);
}


void Border::moveTo(int x, int y) {
    XWindowChanges wc;
    wc.x = x - xIndent();
    wc.y = y - yIndent();
    XConfigureWindow(display(), m_parent, CWX | CWY, &wc);
//    gtk_widget_draw_default(m_labelGtk);
}


void Border::map() {
    if (m_parent == root()) {
        fprintf(stderr, "wmG: bad parent in Border::map()\n");
    } else {
        XMapWindow(display(), m_parent);
        if (m_client->m_hasTitle == True) {
            XMapWindow(display(), m_tab);
//            gtk_widget_draw_default(m_labelGtk);
            XMapWindow(display(), m_hideButton);
            XMapWindow(display(), m_closeButton);
        }
    }
}


void Border::mapRaised() {
    if (m_parent == root()) {
        fprintf(stderr, "wmG: bad parent in Border::mapRaised()\n");
    } else {
        XMapRaised(display(), m_parent);
        if (m_client->m_hasTitle == True) {
            XMapWindow(display(), m_tab);
            XMapRaised(display(), GTK_XWINDOW(m_tabGtk));
//            gtk_widget_draw_default(m_labelGtk);
            XMapRaised(display(), m_hideButton);
            XMapRaised(display(), m_closeButton);
        }
    }
}


void Border::lower() {
    XLowerWindow(display(), m_parent);
}


void Border::unmap() {
    if (m_parent == root()) {
        fprintf(stderr, "wmG: bad parent in Border::unmap()\n");
    } else {
        XUnmapWindow(display(), m_parent);
        if (m_client->m_hasTitle == True) {
            XUnmapWindow(display(), m_tab);
            XUnmapWindow(display(), m_hideButton);
            XUnmapWindow(display(), m_closeButton);
        }
    }
}

void Border::reparent() {
    XReparentWindow(display(), m_child, m_parent, xIndent(), yIndent());
}


syntax highlighted by Code2HTML, v. 0.9.1