/* Copyright (c) 1999 Decklin Foster <fosterd@hartwick.edu>
   Copyright (c) 2000 Linus Nilsson <d96ln@efd.lth.se> */



#include "yawm.h"
#include <stdio.h>
#include <time.h>
#include <sys/time.h>



#define DYN_HEIGHT (!c->shaded ? c->height + 3*opt_bw : 2*opt_bw)



void draw_outline(Client *c) {
	char buf[40];

	XDrawRectangle(dpy, root, invert_gc,
		       c->x + opt_bw/2, 
		       c->y - theight(c) + opt_bw/2,
		       c->width + opt_bw, 
		       c->height + theight(c) + opt_bw);
	
	XDrawLine(dpy, root, invert_gc, 
		  c->x + opt_bw, 
		  c->y + opt_bw/2,
		  c->x + c->width + opt_bw, 
		  c->y + opt_bw/2);

	sprintf(buf, "%dx%d+%d+%d", c->width, c->height, c->x, c->y);
	
	XDrawString(dpy, root, invert_gc,
		    c->x + c->width - XTextWidth(font, buf, strlen(buf)) - 
		    SPACE,
		    c->y + c->height - SPACE,
		    buf, 
		    strlen(buf));
}



void get_mouse_position(int *x, int *y) {
	Window dw1, dw2;
	int t1, t2;
	unsigned int t3;

	XQueryPointer(dpy, root, &dw1, &dw2, x, y, &t1, &t2, &t3);
}



void fix_size(Client *c) {
	int basex;
	int basey;

	if (c->size->flags & PResizeInc) {
		basex = (c->size->flags & PBaseSize) ? c->size->base_width :
			(c->size->flags & PMinSize) ? c->size->min_width : 0;
		basey = (c->size->flags & PBaseSize) ? c->size->base_height :
			(c->size->flags & PMinSize) ? c->size->min_height : 0;
		c->width -= (c->width - basex) % c->size->width_inc;
		c->height -= (c->height - basey) % c->size->height_inc;
	}

	if (c->size->flags & PMinSize) {
		if (c->width < c->size->min_width) {
			c->width = c->size->min_width;
		}
		if (c->height < c->size->min_height) {
			c->height = c->size->min_height;
		}
	}

	if (c->size->flags & PMaxSize) {
		if (c->width > c->size->max_width) {
			c->width = c->size->max_width;
		}
		if (c->height > c->size->max_height) {
			c->height = c->size->max_height;
		}
	}
}



void recalculate_sweep(Client *c, int x1, int y1, int x2, int y2) {
	int basex, basey;

	c->width = abs(x1 - x2) - opt_bw;
	c->height = abs(y1 - y2) - opt_bw;

	if (c->size->flags & PResizeInc) {
		basex = (c->size->flags & PBaseSize) ? c->size->base_width :
			(c->size->flags & PMinSize) ? c->size->min_width : 0;
		basey = (c->size->flags & PBaseSize) ? c->size->base_height :
			(c->size->flags & PMinSize) ? c->size->min_height : 0;
		c->width -= (c->width - basex) % c->size->width_inc;
		c->height -= (c->height - basey) % c->size->height_inc;
	}

	if (c->size->flags & PMinSize) {
		if (c->width < c->size->min_width) {
			c->width = c->size->min_width;
		}
		if (c->height < c->size->min_height) {
			c->height = c->size->min_height;
		}
	}

	if (c->size->flags & PMaxSize) {
		if (c->width > c->size->max_width) {
			c->width = c->size->max_width;
		}
		if (c->height > c->size->max_height) {
			c->height = c->size->max_height;
		}
	}

	c->x = (x1 <= x2) ? x1 : x1 - c->width;
	c->y = (y1 <= y2) ? y1 : y1 - c->height;
}



void sweep(Client *c) {
	XEvent ev;
	int old_cx = c->x;
	int old_cy = c->y;

	if (!grab(root, MouseMask, resize_curs)) {
		return;
	}
	XGrabServer(dpy);

	draw_outline(c);
	setmouse(c->window, c->width, c->height);
	for (;;) {
		XMaskEvent(dpy, MouseMask, &ev);
		switch (ev.type) {
			case MotionNotify:
				draw_outline(c); /* clear */
				recalculate_sweep(c, old_cx, old_cy, 
						  ev.xmotion.x, ev.xmotion.y);
				draw_outline(c);
				break;
			case ButtonRelease:
				draw_outline(c); /* clear */
				XUngrabServer(dpy);
				ungrab();
				return;
		}
	}
}



void move(Client *c) {
	XEvent ev;
	int x1, y1;
	int old_cx = c->x;
	int old_cy = c->y;
	int first_motion = 1;
	int stepx;
	int stepy;
	int moved = 0;
	long old_time;
	long new_time;
        struct timeval mytp;

	if (!grab(root, MouseMask, move_curs)) {
		return;
	}
	get_mouse_position(&x1, &y1);

        gettimeofday(&mytp, NULL);
	old_time = mytp.tv_usec;
						 
	for (;;) {
		XMaskEvent(dpy, MouseMask | ExposureMask | PropertyChangeMask | SubstructureRedirectMask, &ev);
		switch (ev.type) {
		case MotionNotify:
			moved = 1;
			stepx = old_cx + (ev.xmotion.x - x1);
			stepy = old_cy + (ev.xmotion.y - y1);
			if (stepx < 0 &&
			    stepx > -EDGE_RESISTANCE) {
				c->x = 0;
			}
			else if (stepx + c->width + 2*opt_bw > 
			        DisplayWidth(dpy, 0) &&
			        stepx + c->width < DisplayWidth(dpy, 0) +
		                EDGE_RESISTANCE) {
		    		c->x = DisplayWidth(dpy, 0) - c->width - 
			        2*opt_bw;
			}
			else {
				c->x = stepx;
			}		
			if (stepy < theight(c) && 
			    stepy > -EDGE_RESISTANCE) {
				c->y = theight(c);
			}
			else if (stepy + DYN_HEIGHT + 
				 TASKBAR_HEIGHT + opt_bw > 
			         DisplayHeight(dpy, 0) &&
			         stepy + DYN_HEIGHT + 
				 TASKBAR_HEIGHT <
				 DisplayHeight(dpy, 0) + EDGE_RESISTANCE) {
		    		c->y = DisplayHeight(dpy, 0) - TASKBAR_HEIGHT -
				       DYN_HEIGHT - opt_bw;
			}
			else {
				c->y = stepy;
			}
			if (first_motion) {
				first_motion = 0;
			}
			else {
				XMoveWindow(dpy, c->parent, c->x, c->y - 
					    theight(c));
				send_config(c);
			}
			break;
		case ButtonRelease:
        		gettimeofday(&mytp, NULL);
			new_time = mytp.tv_usec;
			if (!moved && (new_time - old_time) <  1000*175) {
				XRaiseWindow(dpy, c->parent);
			}
			ungrab();
			return;
		case Expose:
			handle_expose_event(&ev.xexpose); 
			break;
	 	case PropertyNotify:
			handle_property_change(&ev.xproperty);
	 	case ConfigureRequest:
			handle_configure_request(&ev.xconfigurerequest);
		default:
#ifdef DEBUG
			show_event(ev);
#endif
			break;
		}
	}
}



void resize(Client *c) {
	if (c) {
		sweep(c);
		XMoveResizeWindow(dpy, c->parent,
				  c->x, c->y - theight(c), c->width, 
				  c->height + theight(c));
		XMoveResizeWindow(dpy, c->window,
				  0, theight(c), c->width, c->height);
		c->stored_x = c->x;
		c->stored_y = c->y;
		c->stored_width = c->width;
		c->stored_height = c->height;
		c->maximized = 0;
		send_config(c);
	}
}



void shade(Client *c) {
	if (c) {
		if (!c->shaded) {
			XResizeWindow(dpy, c->parent,
			              c->width, theight(c) - opt_bw);
			c->shaded = 1;
		}
		else {
			XResizeWindow(dpy, c->parent,
				      c->width, c->height + theight(c));
			c->shaded = 0;
		}
		send_config(c);
	}
}



void maximize(Client *c) 
{
	if (c) {
		if (!c->maximized) {
			c->stored_x = c->x;
			c->stored_y = c->y;
			c->stored_width = c->width;
			c->stored_height = c->height;
			c->x = 0;
			c->y = theight(c);
			c->width = DisplayWidth(dpy, 0) - 2*opt_bw;
			c->height = DisplayHeight(dpy, 0) - TASKBAR_HEIGHT -
				    theight(c) - 4*opt_bw;
			fix_size(c);
		        XMoveResizeWindow(dpy, c->parent,
				          c->x, c->y - theight(c), 
					  c->width, c->height + theight(c));
			XMoveResizeWindow(dpy, c->window, 
					  0, theight(c), 
					  c->width, c->height);
			c->maximized = 1;
			c->shaded = 0;
		}
		else {
			c->x = c->stored_x;
			c->y = c->stored_y;
			c->width = c->stored_width;
			c->height = c->stored_height;
			c->maximized = 0;
		        XMoveResizeWindow(dpy, c->parent,
				          c->x, c->y - theight(c), 
					  c->width, c->height + theight(c));
			XMoveResizeWindow(dpy, c->window, 
					  0, theight(c), 
					  c->width, c->height);
		}
		send_config(c);
	}
}



void maximize_vertically(Client *c) {
	if (c) {
		if (!c->maximized) {
			c->stored_x = c->x;
			c->stored_y = c->y;
			c->stored_width = c->width;
			c->stored_height = c->height;
			c->y = theight(c);
			c->height = DisplayHeight(dpy, 0) - TASKBAR_HEIGHT -
				    theight(c) - 3*opt_bw;
			fix_size(c);
		        XMoveResizeWindow(dpy, c->parent,
				          c->x, c->y - theight(c), 
					  c->width, c->height + theight(c));
			XMoveResizeWindow(dpy, c->window, 
					  0, theight(c), 
					  c->width, c->height);
			c->maximized = 1;
		}
		else {
			c->x = c->stored_x;
			c->y = c->stored_y;
			c->width = c->stored_width;
			c->height = c->stored_height;
			c->maximized = 0;
		        XMoveResizeWindow(dpy, c->parent,
				          c->x, c->y - theight(c), 
					  c->width, c->height + theight(c));
			XMoveResizeWindow(dpy, c->window, 
					  0, theight(c), 
					  c->width, c->height);
		}
		send_config(c);
	}
}



void hide(Client *c) {
	if (c) {
		c->ignore_unmap++;
		XUnmapWindow(dpy, c->parent);
		XUnmapWindow(dpy, c->window);
		set_wm_state(c, IconicState);
		c->minimized = 1;
	} 
}



void unhide(Client *c) {
	if (c) {
		XMapWindow(dpy, c->window);
		XMapRaised(dpy, c->parent);
		set_wm_state(c, NormalState);
		c->minimized = 0;
	}
}


syntax highlighted by Code2HTML, v. 0.9.1