/* (C)opyright MMVI-MMVII Kris Maglione <fbsdaemon@gmail.com>
 * See LICENSE file for license details.
 */
#include <stdlib.h>
#include <string.h>
#include "wmii.h"

Frame *
create_frame(Client *c, View *v) {
	static ushort id = 1;
	Frame *f = emallocz(sizeof(Frame));

	f->id = id++;
	f->client = c;
	f->view = v;
	if(c->sel) {
		f->revert = c->sel->revert;
		f->rect = c->sel->rect;
	}
	else{
		c->sel = f;
		f->revert = f->rect = c->rect;
		f->revert.width = f->rect.width += 2 * def.border;
		f->revert.height = f->rect.height += frame_delta_h();
	}
	f->collapsed = False;

	return f;
}

void
remove_frame(Frame *f) {
	Area *a;
	Frame **ft;

	a = f->area;
	for(ft = &a->frame; *ft; ft=&(*ft)->anext)
		if(*ft == f) break;
	*ft = f->anext;

	if(a->floating) {
		for(ft = &a->stack; *ft; ft=&(*ft)->snext)
			if(*ft == f) break;
		*ft = f->snext;
	}
}

void
insert_frame(Frame *pos, Frame *f, Bool before) {
	Frame *ft, **p;
	Area *a = f->area;

	if(before) {
		for(ft=a->frame; ft; ft=ft->anext)
			if(ft->anext == pos) break;
		pos=ft;
	}
	p = &a->frame;
	if(pos)
		p = &pos->anext;
	f->anext = *p;
	*p = f;

	if(a->floating) {
		f->snext = a->stack;
		a->stack = f;
	}
}

void
frame2client(XRectangle *r) {
	r->width = max(r->width - def.border * 2, 1);
	r->height = max(r->height - frame_delta_h(), 1);
}

void
client2frame(XRectangle *r) {
	r->width += def.border * 2;
	r->height += frame_delta_h();
}

void
resize_frame(Frame *f, XRectangle *r) {
	BlitzAlign stickycorner;
	Client *c;

	c = f->client;
	stickycorner = get_sticky(&f->rect, r);

	f->rect = *r;
	f->crect = *r;
	apply_sizehints(c, &f->crect, f->area->floating, True, stickycorner);

	if(f->area->floating)
		f->rect = f->crect;

	frame2client(&f->crect);

	if(f->crect.height < labelh(&def.font))
		f->collapsed = True;
	else
		f->collapsed = False;

	if(f->crect.width < labelh(&def.font)) {
		f->rect.width = frame_delta_h();
		f->collapsed = True;
	}

	if(f->collapsed) {
		f->rect.height = labelh(&def.font);
		f->crect = f->rect;
	}
	f->crect.y = labelh(&def.font);
	f->crect.x = (f->rect.width - f->crect.width) / 2;
	

	if(f->area->floating) {
		if(c->fullscreen) {
			f->crect.width = screen->rect.width;
			f->crect.height = screen->rect.height;
			f->rect = f->crect;
			client2frame(&f->rect);
			f->rect.x = -def.border;
			f->rect.y = -labelh(&def.font);
		}else
			check_frame_constraints(&f->rect);
	}
}

void
set_frame_cursor(Frame *f, int x, int y) {
	XRectangle r;
	Cursor cur;

	if(!ispointinrect(x, y, &f->titlebar)
	 &&!ispointinrect(x, y, &f->crect)) {
	 	r = f->rect;
	 	r.x = 0;
	 	r.y = 0;
	 	cur = cursor_of_quad(quadofcoord(&r, x, y));
		set_cursor(f->client, cur);
	}else
		set_cursor(f->client, cursor[CurNormal]);
}

Bool
frame_to_top(Frame *f) {
	Frame **tf;
	Area *a;

	a = f->area;
	if(!a->floating || f == a->stack)
		return False;
	for(tf=&a->stack; *tf; tf=&(*tf)->snext)
		if(*tf == f) break;
	*tf = f->snext;
	f->snext = a->stack;
	a->stack = f;
	update_client_grab(f->client);
	return True;
}

void
swap_frames(Frame *fa, Frame *fb) {
	XRectangle trect;
	Area *a;
	Frame **fp_a, **fp_b, *ft;

	if(fa == fb) return;

	a = fa->area;
	for(fp_a = &a->frame; *fp_a; fp_a = &(*fp_a)->anext)
		if(*fp_a == fa) break;
	a = fb->area;
	for(fp_b = &a->frame; *fp_b; fp_b = &(*fp_b)->anext)
		if(*fp_b == fb) break;

	if(fa->anext == fb) {
		*fp_a = fb;
		fa->anext = fb->anext;
		fb->anext = fa;
	} else if(fb->anext == fa) {
		*fp_b = fa;
		fb->anext = fa->anext;
		fa->anext = fb;
	} else {
		*fp_a = fb;
		*fp_b = fa;
		ft = fb->anext;
		fb->anext = fa->anext;
		fa->anext = ft;
	}

	if(fb->area->sel == fb)
		fb->area->sel = fa;
	if(fa->area->sel == fa)
		fa->area->sel = fb;

	fb->area = fa->area;
	fa->area = a;

	trect = fa->rect;
	fa->rect = fb->rect;
	fb->rect = trect;
}

void
focus_frame(Frame *f, Bool restack) {
	Frame *old, *old_in_a;
	View *v;
	Area *a, *old_a;

	a = f->area;
	v = f->view;
	old = v->sel->sel;
	old_a = v->sel;
	old_in_a = a->sel;

	a->sel = f;

	if(a != old_a)
		focus_area(f->area);

	if(v != screen->sel)
		return;

	focus_client(f->client);

	if(!a->floating
	&& ((a->mode == Colstack) || (a->mode == Colmax)))
		arrange_column(a, False);

	if((f != old)
	&& (f->area == old_a))
			write_event("ClientFocus 0x%x\n", f->client->win);

	if(restack)
		restack_view(v);
}

int
frame_delta_h() {
	return def.border + labelh(&def.font);
}

void
draw_frame(Frame *f) {
	BlitzBrush br = { 0 };
	Frame *tf;

	br.blitz = &blz;
	br.font = &def.font;
	br.drawable = pmap;
	br.gc = f->client->gc;
	if(f->client == screen->focus)
		br.color = def.focuscolor;
	else
		br.color = def.normcolor;
	if(!f->area->floating && f->area->mode == Colmax)
		for(tf = f->area->frame; tf; tf=tf->anext)
			if(tf->client == screen->focus) {
				br.color = def.focuscolor;
				break;
			}

	br.rect = f->rect;
	br.rect.x = 0;
	br.rect.y = 0;
	draw_tile(&br);

	br.rect.x += def.font.height - 3;
	br.rect.width -= br.rect.x;
	br.rect.height = labelh(&def.font);
	draw_label(&br, f->client->name);

	br.border = 1;
	br.rect.width += br.rect.x;
	br.rect.x = 0;
	f->titlebar.x = br.rect.x + 3;
	f->titlebar.height = br.rect.height - 3;
	f->titlebar.y = br.rect.y + 3;
	f->titlebar.width = br.rect.width - 6;
	draw_border(&br);
	br.rect.height = f->rect.height;
	if(def.border)
		draw_border(&br);

	if(f->client->urgent)
		br.color.bg = br.color.fg;
	br.rect.x = 2;
	br.rect.y = 2;
	br.rect.height = labelh(&def.font) - 4;
	br.rect.width = def.font.height - 3;
	f->grabbox = br.rect;
	draw_tile(&br);

	XCopyArea(
		/* display */	blz.dpy,
		/* src */	pmap,
		/* dest */	f->client->framewin,
		/* gc */	f->client->gc,
		/* x, y */	0, 0,
		/* width */	f->rect.width,
		/* height */	f->rect.height,
		/* dest_x */	0,
		/* dest_y */	0
		);
	XSync(blz.dpy, False);
}

void
draw_frames() {
	Client *c;

	for(c=client; c; c=c->next)
		if(c->sel && c->sel->view == screen->sel)
			draw_frame(c->sel);
}

void
check_frame_constraints(XRectangle *rect) {
	int max_height;
	int barheight;

	barheight = screen->brect.height;
	max_height = screen->rect.height - barheight;

	if(rect->height > max_height)
		rect->height = max_height;
	if(rect->width > screen->rect.width)
		rect->width = screen->rect.width;
	if(rect->x + barheight > screen->rect.width)
		rect->x = screen->rect.width - barheight;
	if(rect->y + barheight > max_height)
		rect->y = max_height - barheight;
	if(r_east(rect) < barheight)
		rect->x = barheight - rect->width;
	if(r_south(rect) < barheight)
		rect->y = barheight - rect->height;
}


syntax highlighted by Code2HTML, v. 0.9.1