#include "BadWM.h"
#include <stdlib.h>
#include <stdio.h>

static int send_xmessage(Window w, Atom a, long x);

Client *find_client(Window w) {
	Client *c;

	for (c = head_client; c; c = c->next)
		if (w == c->parent || w == c->window)
			return c;
	return NULL;
}

static void __set_wm_state(const Window win, const Atom a, int state, long vis) {
	long data[2];

	data[0] = (long) state;
	data[1] = vis;

	XChangeProperty(dpy, win, a, a,
		32, PropModeReplace, (unsigned char *)data, 2);
}
void set_wm_state(Client *c, int state) {
	/* iconify window and set state */
	__set_wm_state(c->window, xa_wm_state, state, None);
}

static long * _g_wm_state(const Window win, const Atom where) {
	Atom real_type;
	int real_format;
	unsigned long n, extra;
	unsigned char *data;

	if ((XGetWindowProperty(dpy, win, where, 0L, 2L, False,
			AnyPropertyType, &real_type, &real_format, &n,
                        &extra, &data) == Success) && n) {
	                return (long *)data;
	}
	return NULL;
}
static int __wm_state(const Window win, const Atom where) {
	long *data, state = WithdrawnState;

	data = _g_wm_state(win, where);
	if (data) {
		state = *data;
		XFree(data);
	}
	return state;
}
int wm_state(Client *c) { return __wm_state(c->window, xa_wm_state); }

void remove_client(Client *c) {
	Client *p;

	XGrabServer(dpy);
	XSetErrorHandler(ignore_xerror);

	if (!quitting) {
		set_wm_state(c, WithdrawnState);
		XRemoveFromSaveSet(dpy, c->window);
	}

	ungravitate(c);
	XSetWindowBorderWidth(dpy, c->window, 1);
	XReparentWindow(dpy, c->window, c->screen->root, c->x, c->y);
	if (c->parent)
		XDestroyWindow(dpy, c->parent);

	if (head_client == c) head_client = c->next;
	else for (p = head_client; p && p->next; p = p->next)
		if (p->next == c) p->next = c->next;

	if (c->size) XFree(c->size);
	if (current == c)
	{
		/* an enter event should set this up again */
		current = NULL;
	}
	free(c);

	XSync(dpy, False);
	XSetErrorHandler(handle_xerror);
	XUngrabServer(dpy);

	if (!current)
	    next();
}

void change_gravity(Client *c, int multiplier) {
	int dx = 0, dy = 0;
	int gravity = (c->size->flags & PWinGravity) ?
		c->size->win_gravity : NorthWestGravity;

	switch (gravity) {
		case NorthWestGravity:
		case SouthWestGravity:
		case NorthEastGravity:
		case StaticGravity:
			dx = c->border;
		case NorthGravity:
			dy = c->border; break;
	}

	c->x += multiplier * dx;
	c->y += multiplier * dy;
}

void send_wm_delete(Client *c) {
	int i, n, found = 0;
	Atom *protocols;

	if (c) {
		if (XGetWMProtocols(dpy, c->window, &protocols, &n)) {
			for (i=0; i<n; i++) if (protocols[i] == xa_wm_delete) found++;
			XFree(protocols);
		}
		if (found) send_xmessage(c->window, xa_wm_protos, xa_wm_delete);
		else XKillClient(dpy, c->window);
	}
}

static int send_xmessage(Window w, Atom a, long x) {
	XEvent ev;

	ev.type = ClientMessage;
	ev.xclient.window = w;
	ev.xclient.message_type = a;
	ev.xclient.format = 32;
	ev.xclient.data.l[0] = x;
	ev.xclient.data.l[1] = CurrentTime;

	return XSendEvent(dpy, w, False, NoEventMask, &ev);
}

void client_to_front(Client *c) {
        Client *prevc;
        if (c==head_client)
          return;
        for (prevc=head_client; prevc && prevc->next!=c; prevc=prevc->next)
          ;
        prevc->next = c->next;
        c->next = head_client;
        head_client = c;
}


void client_update_current(Client *c, Client *newcurrent) {
	if (c) {
		if (c->vdesk == STICKY)
			XSetWindowBackground(dpy, c->parent, c == newcurrent ? c->screen->fc.pixel : c->screen->bg.pixel);
		else
			XSetWindowBackground(dpy, c->parent, c == newcurrent ? c->screen->fg.pixel : c->screen->bg.pixel);
		XClearWindow(dpy, c->parent);
	}
	current = newcurrent;
}

void focus_client( Client *c )
{
        int wdesk;
        wdesk = c->vdesk;
        if (wdesk != vdesk && wdesk != STICKY)
           return;
        client_update_current(current, c);
        client_update_current(c, current);
        XSetInputFocus(dpy, c->window, RevertToPointerRoot, CurrentTime);
        grab_button(c->parent, Mod4Mask, AnyButton);
}
