/*
 * Copyright (c) 2006 Darryll Truchan <moppsy@comcast.net>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <beryl.h>
#include <X11/Xatom.h>

/* defaults */
#define PUT_SPEED_DEFAULT       2.5f
#define PUT_SPEED_MIN           0.1f
#define PUT_SPEED_MAX           50.0f
#define PUT_SPEED_PRECISION     0.1f

#define PUT_TIMESTEP_DEFAULT    0.5f
#define PUT_TIMESTEP_MIN        0.1f
#define PUT_TIMESTEP_MAX        50.0f
#define PUT_TIMESTEP_PRECISION  0.1f

#define PUT_LEFT_PAD_DEFAULT    0
#define PUT_LEFT_PAD_MIN        0
#define PUT_LEFT_PAD_MAX        500

#define PUT_TOP_PAD_DEFAULT     0
#define PUT_TOP_PAD_MIN         0
#define PUT_TOP_PAD_MAX         500

#define PUT_RIGHT_PAD_DEFAULT   0
#define PUT_RIGHT_PAD_MIN       0
#define PUT_RIGHT_PAD_MAX       500

#define PUT_BOTTOM_PAD_DEFAULT  0
#define PUT_BOTTOM_PAD_MIN      0
#define PUT_BOTTOM_PAD_MAX      500

#define PUT_RESTORE_MODIFIERS_DEFAULT       CompSuperMask
#define PUT_RESTORE_KEY_DEFAULT             "KP_Insert"

#define PUT_CENTER_MODIFIERS_DEFAULT        CompSuperMask
#define PUT_CENTER_KEY_DEFAULT              "KP_Begin"

#define PUT_LEFT_MODIFIERS_DEFAULT          CompSuperMask
#define PUT_LEFT_KEY_DEFAULT                "KP_Left"

#define PUT_TOPLEFT_MODIFIERS_DEFAULT       CompSuperMask
#define PUT_TOPLEFT_KEY_DEFAULT             "KP_Home"

#define PUT_TOP_MODIFIERS_DEFAULT           CompSuperMask
#define PUT_TOP_KEY_DEFAULT                 "KP_Up"

#define PUT_TOPRIGHT_MODIFIERS_DEFAULT      CompSuperMask
#define PUT_TOPRIGHT_KEY_DEFAULT            "KP_Prior"

#define PUT_RIGHT_MODIFIERS_DEFAULT         CompSuperMask
#define PUT_RIGHT_KEY_DEFAULT               "KP_Right"

#define PUT_BOTTOMRIGHT_MODIFIERS_DEFAULT   CompSuperMask
#define PUT_BOTTOMRIGHT_KEY_DEFAULT         "KP_Next"

#define PUT_BOTTOM_MODIFIERS_DEFAULT        CompSuperMask
#define PUT_BOTTOM_KEY_DEFAULT              "KP_Down"

#define PUT_BOTTOMLEFT_MODIFIERS_DEFAULT    CompSuperMask
#define PUT_BOTTOMLEFT_KEY_DEFAULT          "KP_End"

#define PUT_POINTER_MODIFIERS_DEFAULT       CompSuperMask
#define PUT_POINTER_KEY_DEFAULT             "z"

#define PUT_SELF_ANIMATE_DEFAULT            TRUE
#define PUT_CENTER_INITIAL_DEFAULT          FALSE
#define PUT_UNFOCUS_WINDOW_DEFAULT          FALSE
#define PUT_WINDOW_CENTER_DEFAULT           FALSE
#define PUT_AVOID_OFFSCREEN_DEFAULT         FALSE

#define PUT_DISPLAY_OPTION_CENTER           0
#define PUT_DISPLAY_OPTION_LEFT             1
#define PUT_DISPLAY_OPTION_TOPLEFT          2
#define PUT_DISPLAY_OPTION_TOP              3
#define PUT_DISPLAY_OPTION_TOPRIGHT         4
#define PUT_DISPLAY_OPTION_RIGHT            5
#define PUT_DISPLAY_OPTION_BOTTOMRIGHT      6
#define PUT_DISPLAY_OPTION_BOTTOM           7
#define PUT_DISPLAY_OPTION_BOTTOMLEFT       8
#define PUT_DISPLAY_OPTION_RESTORE          9
#define PUT_DISPLAY_OPTION_VIEWPORT_LEFT    10
#define PUT_DISPLAY_OPTION_VIEWPORT_RIGHT   11
#define PUT_DISPLAY_OPTION_VIEWPORT         12
#define PUT_DISPLAY_OPTION_VIEWPORT_1       13
#define PUT_DISPLAY_OPTION_VIEWPORT_2       14
#define PUT_DISPLAY_OPTION_VIEWPORT_3       15
#define PUT_DISPLAY_OPTION_VIEWPORT_4       16
#define PUT_DISPLAY_OPTION_VIEWPORT_5       17
#define PUT_DISPLAY_OPTION_VIEWPORT_6       18
#define PUT_DISPLAY_OPTION_VIEWPORT_7       19
#define PUT_DISPLAY_OPTION_VIEWPORT_8       20
#define PUT_DISPLAY_OPTION_VIEWPORT_9       21
#define PUT_DISPLAY_OPTION_VIEWPORT_10      22
#define PUT_DISPLAY_OPTION_VIEWPORT_11      23
#define PUT_DISPLAY_OPTION_VIEWPORT_12      24
#define PUT_DISPLAY_OPTION_EXACT            25
#define PUT_DISPLAY_OPTION_POINTER          26
#define PUT_DISPLAY_OPTION_VIEWPORT_UP      27
#define PUT_DISPLAY_OPTION_VIEWPORT_DOWN    28
#define PUT_DISPLAY_OPTION_NUM              29

#define PUT_SCREEN_OPTION_SPEED             0
#define PUT_SCREEN_OPTION_TIMESTEP          1
#define PUT_SCREEN_OPTION_LEFT_PAD          2
#define PUT_SCREEN_OPTION_TOP_PAD           3
#define PUT_SCREEN_OPTION_RIGHT_PAD         4
#define PUT_SCREEN_OPTION_BOTTOM_PAD        5
#define PUT_SCREEN_OPTION_UNFOCUS_WINDOW    6
#define PUT_SCREEN_OPTION_WINDOW_CENTER     7
#define PUT_SCREEN_OPTION_AVOID_OFFSCREEN   8
#define PUT_SCREEN_OPTION_NUM               9

#define GET_PUT_DISPLAY(d) ((PutDisplay *) (d)->privates[displayPrivateIndex].ptr)
#define PUT_DISPLAY(d) PutDisplay *pd = GET_PUT_DISPLAY (d)
#define GET_PUT_SCREEN(s, pd) ((PutScreen *) (s)->privates[(pd)->screenPrivateIndex].ptr)
#define PUT_SCREEN(s) PutScreen *ps = GET_PUT_SCREEN (s, GET_PUT_DISPLAY (s->display))
#define GET_PUT_WINDOW(w, ps) ((PutWindow *) (w)->privates[(ps)->windowPrivateIndex].ptr)
#define PUT_WINDOW(w) PutWindow *pw = GET_PUT_WINDOW  (w, GET_PUT_SCREEN  (w->screen, GET_PUT_DISPLAY (w->screen->display)))

#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))

/* using the plane plugin flag
 * seemed appropriate as a global
 */
static Bool usePlane = FALSE;

static int displayPrivateIndex;

typedef enum
{
	PutUnknown = 0,
	PutBottomLeft = 1,
	PutBottom = 2,
	PutBottomRight = 3,
	PutLeft = 4,
	PutCenter = 5,
	PutRight = 6,
	PutTopLeft = 7,
	PutTop = 8,
	PutTopRight = 9,
	PutRestore = 10,
	PutViewport = 11,
	PutViewportLeft = 12,
	PutViewportRight = 13,
	PutExact = 14,
	PutPointer = 15,
	PutViewportUp = 16,
	PutViewportDown = 17
} PutType;

typedef struct _PutDisplay
{
	int screenPrivateIndex;
	CompOption opt[PUT_DISPLAY_OPTION_NUM];	/* array of display options      */
	HandleEventProc handleEvent;	/* handle event function pointer */
	Atom berylPutWindowAtom;	/* client event atom             */
} PutDisplay;

typedef struct _PutScreen
{
	int windowPrivateIndex;
	CompOption opt[PUT_SCREEN_OPTION_NUM];	/* array of screen options  */
	PreparePaintScreenProc preparePaintScreen;	/* function pointer         */
	DonePaintScreenProc donePaintScreen;	/* function pointer         */
	PaintScreenProc paintScreen;	/* function pointer         */
	PaintWindowProc paintWindow;	/* function pointer         */
	float speed;				/* animation speed          */
	float timestep;				/* animation time step      */
	int moreAdjust;				/* animation flag           */
	int grabIndex;				/* screen grab index        */
	int padLeft, padTop, padRight, padBottom;	/* position padding         */
	Bool vpMoving;				/* viewport move flag       */
	Bool unfocusWindow;			/* unfocus after move flag  */
	Bool windowcenter;			/* put pointer - window center */
	Bool avoidoffscreen;		/* avoid windows offscreen using put pointer */
	CompWindow *current;		/* window being moved       */
} PutScreen;

typedef struct _PutWindow
{
	GLfloat xVelocity, yVelocity;	/* animation velocity       */
	GLfloat tx, ty;				/* animation translation    */
	int dx, dy;					/* change in position       */
	int x, y;					/* current position         */
	int lastX, lastY;			/* starting position        */

	Bool adjust;				/* animation flag           */
} PutWindow;

static Bool
putSetScreenOption(CompScreen * screen, char *name, CompOptionValue * value)
{
	CompOption *o;
	int index;

	PUT_SCREEN(screen);

	o = compFindOption(ps->opt, NUM_OPTIONS(ps), name, &index);
	if (!o)
		return FALSE;

	switch (index)
	{
	case PUT_SCREEN_OPTION_SPEED:
		if (compSetFloatOption(o, value))
		{
			ps->speed = o->value.f;
			return TRUE;
		}
		break;

	case PUT_SCREEN_OPTION_TIMESTEP:
		if (compSetFloatOption(o, value))
		{
			ps->timestep = o->value.f;
			return TRUE;
		}
		break;

	case PUT_SCREEN_OPTION_LEFT_PAD:
		if (compSetIntOption(o, value))
		{
			ps->padLeft = o->value.i;
			return TRUE;
		}
		break;

	case PUT_SCREEN_OPTION_TOP_PAD:
		if (compSetIntOption(o, value))
		{
			ps->padTop = o->value.i;
			return TRUE;
		}
		break;

	case PUT_SCREEN_OPTION_RIGHT_PAD:
		if (compSetIntOption(o, value))
		{
			ps->padRight = o->value.i;
			return TRUE;
		}
		break;

	case PUT_SCREEN_OPTION_BOTTOM_PAD:
		if (compSetIntOption(o, value))
		{
			ps->padBottom = o->value.i;
			return TRUE;
		}
		break;

	case PUT_SCREEN_OPTION_UNFOCUS_WINDOW:
		if (compSetBoolOption(o, value))
		{
			ps->unfocusWindow = o->value.b;
			return TRUE;
		}
		break;

	case PUT_SCREEN_OPTION_WINDOW_CENTER:
		if (compSetBoolOption(o, value))
		{
			ps->windowcenter = o->value.b;
			return TRUE;
		}
		break;

	case PUT_SCREEN_OPTION_AVOID_OFFSCREEN:
		if (compSetBoolOption(o, value))
		{
			ps->avoidoffscreen = o->value.b;
			return TRUE;
		}
		break;

	default:
		break;
	}

	return FALSE;
}

static void putScreenInitOptions(PutScreen * ps)
{
	CompOption *o;

	o = &ps->opt[PUT_SCREEN_OPTION_SPEED];
	o->advanced = False;
	o->name = "speed";
	o->group = N_("Animation");
	o->subGroup = N_("");
	o->displayHints = "";
	o->shortDesc = N_("Animation Speed");
	o->longDesc = N_("Animation Speed.");
	o->type = CompOptionTypeFloat;
	o->value.f = PUT_SPEED_DEFAULT;
	o->rest.f.min = PUT_SPEED_MIN;
	o->rest.f.max = PUT_SPEED_MAX;
	o->rest.f.precision = PUT_SPEED_PRECISION;

	o = &ps->opt[PUT_SCREEN_OPTION_TIMESTEP];
	o->advanced = False;
	o->name = "timestep";
	o->group = N_("Animation");
	o->subGroup = N_("");
	o->displayHints = "";
	o->shortDesc = N_("Timestep");
	o->longDesc = N_("Animation Timestep.");
	o->type = CompOptionTypeFloat;
	o->value.f = PUT_TIMESTEP_DEFAULT;
	o->rest.f.min = PUT_TIMESTEP_MIN;
	o->rest.f.max = PUT_TIMESTEP_MAX;
	o->rest.f.precision = PUT_TIMESTEP_PRECISION;

	o = &ps->opt[PUT_SCREEN_OPTION_LEFT_PAD];
	o->advanced = False;
	o->name = "pad_left";
	o->group = N_("Misc. options");
	o->subGroup = N_("Padding");
	o->displayHints = "";
	o->shortDesc = N_("Pad Left");
	o->longDesc =
			N_
			("Number of pixels from the Left edge where the active window will come to rest.");
	o->type = CompOptionTypeInt;
	o->value.i = PUT_LEFT_PAD_DEFAULT;
	o->rest.i.min = PUT_LEFT_PAD_MIN;
	o->rest.i.max = PUT_LEFT_PAD_MAX;

	o = &ps->opt[PUT_SCREEN_OPTION_TOP_PAD];
	o->advanced = False;
	o->name = "pad_top";
	o->group = N_("Misc. options");
	o->subGroup = N_("Padding");
	o->displayHints = "";
	o->shortDesc = N_("Pad Top");
	o->longDesc =
			N_
			("Number of pixels from the Top edge where the active window will come to rest.");
	o->type = CompOptionTypeInt;
	o->value.i = PUT_TOP_PAD_DEFAULT;
	o->rest.i.min = PUT_TOP_PAD_MIN;
	o->rest.i.max = PUT_TOP_PAD_MAX;

	o = &ps->opt[PUT_SCREEN_OPTION_RIGHT_PAD];
	o->advanced = False;
	o->name = "pad_right";
	o->group = N_("Misc. options");
	o->subGroup = N_("Padding");
	o->displayHints = "";
	o->shortDesc = N_("Pad Right");
	o->longDesc =
			N_
			("Number of pixels from the Right edge where the active window will come to rest.");
	o->type = CompOptionTypeInt;
	o->value.i = PUT_RIGHT_PAD_DEFAULT;
	o->rest.i.min = PUT_RIGHT_PAD_MIN;
	o->rest.i.max = PUT_RIGHT_PAD_MAX;

	o = &ps->opt[PUT_SCREEN_OPTION_BOTTOM_PAD];
	o->advanced = False;
	o->name = "pad_bottom";
	o->group = N_("Misc. options");
	o->subGroup = N_("Padding");
	o->displayHints = "";
	o->shortDesc = N_("Pad Bottom");
	o->longDesc =
			N_
			("Number of pixels from the Bottom edge where the active window will come to rest.");
	o->type = CompOptionTypeInt;
	o->value.i = PUT_BOTTOM_PAD_DEFAULT;
	o->rest.i.min = PUT_BOTTOM_PAD_MIN;
	o->rest.i.max = PUT_BOTTOM_PAD_MAX;

	o = &ps->opt[PUT_SCREEN_OPTION_UNFOCUS_WINDOW];
	o->advanced = False;
	o->name = "unfocus_window";
	o->group = N_("Misc. options");
	o->subGroup = N_("");
	o->displayHints = "";
	o->shortDesc = N_("Unfocus Window");
	o->longDesc = N_("Unfocus Windows that are moved off the viewport.");
	o->type = CompOptionTypeBool;
	o->value.b = PUT_UNFOCUS_WINDOW_DEFAULT;

	o = &ps->opt[PUT_SCREEN_OPTION_WINDOW_CENTER];
	o->advanced = False;
	o->name = "window_center";
	o->group = N_("Misc. options");
	o->subGroup = N_("");
	o->displayHints = "";
	o->shortDesc = N_("Window Center");
	o->longDesc = N_("Put pointer uses the Center of the Window.");
	o->type = CompOptionTypeBool;
	o->value.b = PUT_WINDOW_CENTER_DEFAULT;

	o = &ps->opt[PUT_SCREEN_OPTION_AVOID_OFFSCREEN];
	o->advanced = False;
	o->name = "avoid_offscreen";
	o->group = N_("Misc. options");
	o->subGroup = N_("");
	o->displayHints = "";
	o->shortDesc = N_("Avoid Offscreen");
	o->longDesc = N_("Avoids putting window borders Offscreen.");
	o->type = CompOptionTypeBool;
	o->value.b = PUT_AVOID_OFFSCREEN_DEFAULT;

}

static CompOption *putGetScreenOptions(CompScreen * screen, int *count)
{
	if (screen)
	{
		PUT_SCREEN(screen);
		*count = NUM_OPTIONS(ps);
		return ps->opt;
	}
	else
	{
		PutScreen *ps = malloc(sizeof(PutScreen));

		putScreenInitOptions(ps);
		*count = NUM_OPTIONS(ps);
		return ps->opt;
	}
}



/*
 * calculate the velocity for the moving window
 */
static int adjustPutVelocity(CompWindow * w)
{
	float dx, dy, adjust, amount;
	float x1, y1;

	PUT_WINDOW(w);

	x1 = pw->lastX + pw->dx;
	y1 = pw->lastY + pw->dy;

	dx = x1 - (pw->lastX + pw->tx);
	dy = y1 - (pw->lastY + pw->ty);

	adjust = dx * 0.15f;
	amount = fabs(dx) * 1.5;
	if (amount < 0.5f)
		amount = 0.5f;
	else if (amount > 5.0f)
		amount = 5.0f;

	pw->xVelocity = (amount * pw->xVelocity + adjust) / (amount + 1.0f);

	adjust = dy * 0.15f;
	amount = fabs(dy) * 1.5f;
	if (amount < 0.5f)
		amount = 0.5f;
	else if (amount > 5.0f)
		amount = 5.0f;

	pw->yVelocity = (amount * pw->yVelocity + adjust) / (amount + 1.0f);

	if (fabs(dx) < 0.1f && fabs(pw->xVelocity) < 0.2f &&
		fabs(dy) < 0.1f && fabs(pw->yVelocity) < 0.2f)
	{
		/* animation done */
		pw->xVelocity = pw->yVelocity = 0.0f;

		pw->tx = x1 - pw->lastX;
		pw->ty = y1 - pw->lastY;

		pw->dx = pw->dy = 0;

		/* sync position with X server */
		syncWindowPosition(w);
		return 0;
	}
	return 1;
}

/*
 * setup for paint screen
 */
static void putPreparePaintScreen(CompScreen * s, int msSinceLastPaint)
{
	PUT_SCREEN(s);

	if (ps->moreAdjust && ps->grabIndex)
	{
		CompWindow *w;
		int steps, dx, dy;
		float amount, chunk;

		amount = msSinceLastPaint * 0.025f * ps->speed;
		steps = amount / (0.5f * ps->timestep);
		if (!steps)
			steps = 1;
		chunk = amount / (float)steps;

		while (steps--)
		{
			ps->moreAdjust = 0;
			for (w = s->windows; w; w = w->next)
			{
				PUT_WINDOW(w);

				if (pw->adjust)
				{
					pw->adjust = adjustPutVelocity(w);
					ps->moreAdjust |= pw->adjust;

					pw->tx += pw->xVelocity * chunk;
					pw->ty += pw->yVelocity * chunk;

					dx = (pw->lastX + pw->tx) - pw->x;
					dy = (pw->lastY + pw->ty) - pw->y;

					moveWindow(w, dx, dy, TRUE, TRUE);

					pw->x += dx;
					pw->y += dy;

				}
			}
			if (!ps->moreAdjust)
			{
				/* unfocus moved window if enabled */
				if (ps->unfocusWindow)
					focusDefaultWindow(s->display);
				break;
			}
		}
	}

	UNWRAP(ps, s, preparePaintScreen);
	(*s->preparePaintScreen) (s, msSinceLastPaint);
	WRAP(ps, s, preparePaintScreen, putPreparePaintScreen);
}

/*
 * after painting clean up
 */
static void putDonePaintScreen(CompScreen * s)
{
	PUT_SCREEN(s);

	if (ps->moreAdjust && ps->grabIndex)
	{
		CompWindow *w;

		for (w = s->windows; w; w = w->next)
		{
			PUT_WINDOW(w);

			if (pw->adjust)
			{
				/* more animating to do */
				addWindowDamage(w);
			}
		}
	}
	else
	{
		if (ps->grabIndex)
		{
			/* release the screen grab */
			/* removeScreenGrab (s, ps->grabIndex, NULL); */
			ps->grabIndex = 0;
			ps->current = NULL;
		}
	}

	UNWRAP(ps, s, donePaintScreen);
	(*s->donePaintScreen) (s);
	WRAP(ps, s, donePaintScreen, putDonePaintScreen);
}

static Bool
putPaintScreen(CompScreen * s, const ScreenPaintAttrib * sAttrib,
			   Region region, int output, unsigned int mask)
{
	Bool status;

	PUT_SCREEN(s);

	if (ps->moreAdjust)
		mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;

	UNWRAP(ps, s, paintScreen);
	status = (*s->paintScreen) (s, sAttrib, region, output, mask);
	WRAP(ps, s, paintScreen, putPaintScreen);

	return status;
}

static Bool
putPaintWindow(CompWindow * w, const WindowPaintAttrib * attrib,
			   Region region, unsigned int mask)
{
	CompScreen *s = w->screen;
	Bool status;

	PUT_SCREEN(s);
	PUT_WINDOW(w);

	if (pw->adjust)
		mask |= PAINT_WINDOW_TRANSFORMED_MASK;

	UNWRAP(ps, s, paintWindow);
	status = (*s->paintWindow) (w, attrib, region, mask);
	WRAP(ps, s, paintWindow, putPaintWindow);

	return status;
}

/*
 * initiate action callback
 */
static Bool
putInitiate(CompDisplay * d, CompAction * action, CompActionState state,
			CompOption * option, int nOption)
{
	CompWindow *w;
	Window xid;
	int px, py, x, y, dx, dy, head, width, height, hx, hy, face,
			face_x, face_y, hdirection, vdirection;
	PutType type;
	XRectangle workArea;
	CompPlugin *p;

	xid = getIntOptionNamed(option, nOption, "window", 0);
	type = getIntOptionNamed(option, nOption, "type", PutCenter);
	px = getIntOptionNamed(option, nOption, "x", 0);
	py = getIntOptionNamed(option, nOption, "y", 0);

	if (!xid)
		xid = d->activeWindow;

	w = findWindowAtDisplay(d, xid);

	if (w)
	{
		PUT_SCREEN(w->screen);
		PUT_WINDOW(w);

		if (!ps->grabIndex)
		{
			/* this will keep put from working while something else has a screen grab */
			if (otherScreenGrabExist(w->screen, "put", 0))
				return FALSE;

			/* we are ok, so grab the screen */
			ps->grabIndex = 1;
			/* pushScreenGrab (w->screen, w->screen->invisibleCursor, "put"); */
		}

		if (ps->grabIndex)
		{
			/* save a pointer to the moving window for later */
			ps->current = w;

			/* reset the viewport moving flag */
			ps->vpMoving = FALSE;

			/* we don't want to do anything with override redirect windows */
			if (w->attrib.override_redirect)
				return FALSE;

			/* we dont want to be moving the desktop, docks, or fullscree window */
			if (w->type & CompWindowTypeDesktopMask ||
				w->type & CompWindowTypeDockMask ||
				w->type & CompWindowTypeFullscreenMask)
			{
				return FALSE;
			}

			/* get the Xinerama head from the options list */
			head = getIntOptionNamed(option, nOption, "head", -1);

			/* no head in options list so we use the current head */
			if (head == -1)
				head = screenGetCurrentOutputDev(w->screen);

			/* make sure the head number is not out of bounds */
			head = MIN(head,w->screen->nOutputDev -1);

			/* some error has occured so we bail out */
			if (head < 0)
				return FALSE;

			/* working area of the screen */
			screenGetOutputDevWorkArea(w->screen, head, &workArea);
			width = workArea.width;
			height = workArea.height;
			hx = workArea.x;
			hy = workArea.y;

			/* the windows location */
			x = w->attrib.x;
			y = w->attrib.y;

			/*
			 * Check to see if we are using the plane plugin
			 * The user could have changed it between initiates
			 */
			for (p = getPlugins(); p; p = p->next)
			{
				if (strcmp(p->vTable->name, "plane") == 0)
					usePlane = TRUE;
			}

			/* handle the put types
			 *
			 */
			switch (type)
			{
			case PutCenter:
				/* center of the screen */
				dx = (width / 2) - (w->width / 2) - (x - hx);
				dy = (height / 2) - (w->height / 2) - (y - hy);
				break;

			case PutLeft:
				/* center of the left edge */
				dx = -(x - hx) + w->input.left + ps->padLeft;
				dy = (height / 2) - (w->height / 2) - (y - hy);
				break;

			case PutTopLeft:
				/* top left corner */
				dx = -(x - hx) + w->input.left + ps->padLeft;
				dy = -(y - hy) + w->input.top + ps->padTop;
				break;

			case PutTop:
				/* center of top edge */
				dx = (width / 2) - (w->width / 2) - (x - hx);
				dy = -(y - hy) + w->input.top + ps->padTop;
				break;

			case PutTopRight:
				/* top right corner */
				dx = width - w->width - (x - hx) -
						w->input.right - ps->padRight;
				dy = -(y - hy) + w->input.top + ps->padTop;
				break;

			case PutRight:
				/* center of right edge */
				dx = width - w->width - (x - hx) -
						w->input.right - ps->padRight;
				dy = (height / 2) - (w->height / 2) - (y - hy);
				break;

			case PutBottomRight:
				/* bottom right corner */
				dx = width - w->width - (x - hx) -
						w->input.right - ps->padRight;
				dy = height - w->height - (y - hy) -
						w->input.bottom - ps->padBottom;
				break;

			case PutBottom:
				/* center of bottom edge */
				dx = (width / 2) - (w->width / 2) - (x - hx);
				dy = height - w->height - (y - hy) -
						w->input.bottom - ps->padBottom;
				break;

			case PutBottomLeft:
				/* bottom left corner */
				dx = -(x - hx) + w->input.left + ps->padLeft;
				dy = height - w->height - (y - hy) -
						w->input.bottom - ps->padBottom;
				break;

			case PutRestore:
				/* back to last position */
				dx = pw->lastX - x;
				dy = pw->lastY - y;
				break;

			case PutViewport:
				/* get the fave to move to from the options list */
				face = getIntOptionNamed(option, nOption, "face", -1);

				/* if it wasn't supplied, bail out */
				if (face < 0)
					return FALSE;

				/* if we are using the plane plugin, we need to handle y movment */
				if (usePlane)
				{
					/* split 1D face value into 2D x and y face */
					face_x = face % w->screen->hsize;
					face_y = face / w->screen->hsize;
				}
				else
				{
					/* we are not using plane, so it must be cube (for now) */
					face_x = face;
					face_y = 0;
				}

				/* take the shortest horizontal path to the destination viewport */
				hdirection = (face_x - w->screen->x);
				if (hdirection > w->screen->hsize / 2)
					hdirection = (hdirection - w->screen->hsize);
				else if (hdirection < -w->screen->hsize / 2)
					hdirection = (hdirection + w->screen->hsize);

				/* we need to do this for the vertical destination viewport too
				 * if we are using plane
				 */
				if (usePlane)
				{
					vdirection = (face_y - w->screen->y);
					if (vdirection > w->screen->vsize / 2)
						vdirection = (vdirection - w->screen->vsize);
					else if (vdirection < -w->screen->hsize / 2)
						vdirection = (vdirection + w->screen->vsize);

					dx = w->screen->width * hdirection;
					dy = w->screen->height * vdirection;
				}
				else
				{
					/* we must be using cube, so we by pass vertical
					 * destination calculations
					 */
					dx = w->screen->width * hdirection;
					dy = 0;
				}

				/* this is a viewport move so we flag it */
				ps->vpMoving = TRUE;
				break;

			case PutViewportLeft:
				/* move to the viewport on the left */
				dx = -w->screen->workArea.width;
				dy = 0;
				ps->vpMoving = TRUE;
				break;

			case PutViewportRight:
				/* move to the viewport on the right */
				dx = w->screen->workArea.width;
				dy = 0;
				ps->vpMoving = TRUE;
				break;

			case PutViewportUp:
				/* move to the viewport above if we are using plane */
				dx = 0;
				dy = 0;
				if (usePlane)
					dy = -w->screen->workArea.height;
				ps->vpMoving = TRUE;
				break;

			case PutViewportDown:
				/* move to the viewport below if we are using plane */
				dx = 0;
				dy = 0;
				if (usePlane)
					dy = w->screen->workArea.height;
				ps->vpMoving = TRUE;
				break;

			case PutExact:
				/* move the window to an exact position */
				if (px < 0)
					/* account for a specified negative position, like geometry without (-0) */
					dx = px +
							w->screen->workArea.width -
							w->width - x - w->input.right;
				else
					dx = px - x + w->input.left;

				if (py < 0)
					/* account for a specified negative position, like geometry without (-0) */
					dy = py +
							w->screen->workArea.height -
							w->height - y - w->input.bottom;
				else
					dy = py - y + w->input.top;

				break;

			case PutPointer:
			{
				/* move the window to the pointers position
				 * using the current quad of the screen to determine
				 * which corner to move to the pointer
				 */
				int rx, ry;
				Window root, child;
				int winx, winy;
				unsigned int pmask;

				/* get the pointers position from the X server */
				XQueryPointer(d->display, w->id,
							  &root, &child, &rx, &ry, &winx, &winy, &pmask);

				if (ps->windowcenter)
				{
					/* window center */
					dx = rx - (w->width / 2) - x;
					dy = ry - (w->height / 2) - y;
				}
				else if (rx <
						 w->screen->workArea.
						 width / 2 && ry < w->screen->workArea.height / 2)
				{
					/* top left quad */
					dx = rx - x + w->input.left;
					dy = ry - y + w->input.top;
				}
				else if (rx <
						 w->screen->workArea.
						 width / 2 && ry >= w->screen->workArea.height / 2)
				{
					/* bottom left quad */
					dx = rx - x + w->input.left;
					dy = ry - w->height - y - w->input.bottom;
				}
				else if (rx >=
						 w->screen->workArea.
						 width / 2 && ry < w->screen->workArea.height / 2)
				{
					/* top right quad */
					dx = rx - w->width - x - w->input.right;
					dy = ry - y + w->input.top;
				}
				else
				{
					/* bottom right quad */
					dx = rx - w->width - x - w->input.right;
					dy = ry - w->height - y - w->input.bottom;
				}
			}
				break;

			default:
				/* if an unknown type is specified, do nothing */
				dx = dy = 0;
				break;
			}

			/* don't do anything if there is nothing to do */
			if (dx != 0 || dy != 0)
			{
				if (ps->avoidoffscreen)
				{
					/* avoids window borders offscreen */
					if ((-(x - hx) + w->input.left + ps->padLeft) > dx)
						dx = -(x - hx) + w->input.left + ps->padLeft;
					else if ((width - w->width -
							  (x - hx) - w->input.right - ps->padRight) < dx)
						dx = width - w->width -
								(x - hx) - w->input.right - ps->padRight;

					if ((-(y - hy) + w->input.top + ps->padTop) > dy)
						dy = -(y - hy) + w->input.top + ps->padTop;
					else if ((height - w->height -
							  (y - hy) -
							  w->input.bottom - ps->padBottom) < dy)
						dy = height - w->height -
								(y - hy) - w->input.bottom - ps->padBottom;
				}
				/* save the windows position in the saveMask
				 * this is used when unmaximizing the window
				 */
				if (w->saveMask & CWX)
					w->saveWc.x += dx;

				if (w->saveMask & CWY)
					w->saveWc.y += dy;

				/* Make sure everyting starts out at the windows current position */
				pw->lastX = pw->x = x;
				pw->lastY = pw->y = y;

				/* save the change in position to the window */
				pw->dx = dx;
				pw->dy = dy;

				/* mark for animation */
				pw->adjust = TRUE;
				ps->moreAdjust = TRUE;

				/* reset values */
				pw->tx = pw->ty = 0;

				/* cause repainting */
				addWindowDamage(w);
			}
		}
	}

	/* tell event.c handleEvent to not call XAllowEvents */
	return FALSE;
}

static Bool
putToViewport(CompDisplay * d, CompAction * action, CompActionState state,
			  CompOption * option, int nOption)
{
	int face, i;

	PUT_DISPLAY(d);

	/* get the face option */
	face = getIntOptionNamed(option, nOption, "face", -1);

	/* if it's not supplied, lets figure it out */
	if (face < 0)
	{
		i = PUT_DISPLAY_OPTION_VIEWPORT_1;

		while (i <= PUT_DISPLAY_OPTION_VIEWPORT_12)
		{
			if (action == &pd->opt[i].value.action)
			{
				face = i - PUT_DISPLAY_OPTION_VIEWPORT_1;

				break;
			}
			i++;
		}
	}

	/* setup the options for putInitiate */
	CompOption o[5];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "face";
	o[2].value.i = face;

	o[3].type = CompOptionTypeInt;
	o[3].name = "type";
	o[3].value.i = PutViewport;

	o[4].type = CompOptionTypeInt;
	o[4].name = "window";
	o[4].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 5);

	return FALSE;
}

static Bool
putViewportLeft(CompDisplay * d, CompAction * action,
				CompActionState state, CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutViewportLeft;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putViewportRight(CompDisplay * d, CompAction * action,
				 CompActionState state, CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutViewportRight;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putViewportUp(CompDisplay * d, CompAction * action, CompActionState state,
			  CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutViewportUp;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putViewportDown(CompDisplay * d, CompAction * action,
				CompActionState state, CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutViewportDown;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
restore(CompDisplay * d, CompAction * action, CompActionState state,
		CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutRestore;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putPointer(CompDisplay * d, CompAction * action, CompActionState state,
		   CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutPointer;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putExact(CompDisplay * d, CompAction * action, CompActionState state,
		 CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutExact;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putCenter(CompDisplay * d, CompAction * action, CompActionState state,
		  CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutCenter;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putLeft(CompDisplay * d, CompAction * action, CompActionState state,
		CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutLeft;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putTopLeft(CompDisplay * d, CompAction * action, CompActionState state,
		   CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutTopLeft;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putTop(CompDisplay * d, CompAction * action, CompActionState state,
	   CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutTop;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putTopRight(CompDisplay * d, CompAction * action, CompActionState state,
			CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutTopRight;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putRight(CompDisplay * d, CompAction * action, CompActionState state,
		 CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutRight;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putBottomRight(CompDisplay * d, CompAction * action, CompActionState state,
			   CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutBottomRight;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putBottom(CompDisplay * d, CompAction * action, CompActionState state,
		  CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutBottom;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static Bool
putBottomLeft(CompDisplay * d, CompAction * action, CompActionState state,
			  CompOption * option, int nOption)
{
	/* setup the options for putInitiate */
	CompOption o[4];

	o[0].type = CompOptionTypeInt;
	o[0].name = "x";
	o[0].value.i = getIntOptionNamed(option, nOption, "x", 0);

	o[1].type = CompOptionTypeInt;
	o[1].name = "y";
	o[1].value.i = getIntOptionNamed(option, nOption, "y", 0);

	o[2].type = CompOptionTypeInt;
	o[2].name = "type";
	o[2].value.i = PutBottomLeft;

	o[3].type = CompOptionTypeInt;
	o[3].name = "window";
	o[3].value.i = getIntOptionNamed(option, nOption, "window", 0);

	putInitiate(d, NULL, 0, o, 4);

	return FALSE;
}

static void putHandleEvent(CompDisplay * d, XEvent * event)
{
	PUT_DISPLAY(d);

	switch (event->type)
	{
		/* handle client events */
	case ClientMessage:
		/* accept the custom atom for putting windows */
		if (event->xclient.message_type == pd->berylPutWindowAtom)
		{
			CompWindow *w;

			w = findWindowAtDisplay(d, event->xclient.window);
			if (w)
			{
				/*
				 * get the values from the xclientmessage event and populate
				 * the options for put initiate
				 *
				 * the format is 32
				 * and the data is
				 * l[0] = x position - unused (for future PutExact)
				 * l[1] = y position - unused (for future PutExact)
				 * l[2] = face number
				 * l[3] = put type, int value from enum
				 * l[4] = Xinerama head number
				 */
				CompOption opt[6];

				opt[0].type = CompOptionTypeInt;
				opt[0].name = "window";
				opt[0].value.i = event->xclient.window;

				opt[1].type = CompOptionTypeInt;
				opt[1].name = "x";
				opt[1].value.i = event->xclient.data.l[0];

				opt[2].type = CompOptionTypeInt;
				opt[2].name = "y";
				opt[2].value.i = event->xclient.data.l[1];

				opt[3].type = CompOptionTypeInt;
				opt[3].name = "face";
				opt[3].value.i = event->xclient.data.l[2];

				opt[4].type = CompOptionTypeInt;
				opt[4].name = "type";
				opt[4].value.i = event->xclient.data.l[3];

				opt[5].type = CompOptionTypeInt;
				opt[5].name = "head";
				opt[5].value.i = event->xclient.data.l[4];

				putInitiate(w->screen->display, NULL, 0, opt, 6);

			}
		}
		break;

	default:
		break;
	}

	UNWRAP(pd, d, handleEvent);
	(*d->handleEvent) (d, event);
	WRAP(pd, d, handleEvent, putHandleEvent);
}

static Bool
putSetDisplayOption(CompDisplay * display, char *name,
					CompOptionValue * value)
{
	CompOption *o;
	int index;

	PUT_DISPLAY(display);

	o = compFindOption(pd->opt, NUM_OPTIONS(pd), name, &index);

	if (!o)
		return FALSE;

	switch (index)
	{
	case PUT_DISPLAY_OPTION_RESTORE:
	case PUT_DISPLAY_OPTION_CENTER:
	case PUT_DISPLAY_OPTION_LEFT:
	case PUT_DISPLAY_OPTION_TOPLEFT:
	case PUT_DISPLAY_OPTION_TOP:
	case PUT_DISPLAY_OPTION_TOPRIGHT:
	case PUT_DISPLAY_OPTION_RIGHT:
	case PUT_DISPLAY_OPTION_BOTTOMRIGHT:
	case PUT_DISPLAY_OPTION_BOTTOM:
	case PUT_DISPLAY_OPTION_BOTTOMLEFT:
	case PUT_DISPLAY_OPTION_VIEWPORT_LEFT:
	case PUT_DISPLAY_OPTION_VIEWPORT_RIGHT:
	case PUT_DISPLAY_OPTION_VIEWPORT_UP:
	case PUT_DISPLAY_OPTION_VIEWPORT_DOWN:
	case PUT_DISPLAY_OPTION_VIEWPORT:
	case PUT_DISPLAY_OPTION_VIEWPORT_1:
	case PUT_DISPLAY_OPTION_VIEWPORT_2:
	case PUT_DISPLAY_OPTION_VIEWPORT_3:
	case PUT_DISPLAY_OPTION_VIEWPORT_4:
	case PUT_DISPLAY_OPTION_VIEWPORT_5:
	case PUT_DISPLAY_OPTION_VIEWPORT_6:
	case PUT_DISPLAY_OPTION_VIEWPORT_7:
	case PUT_DISPLAY_OPTION_VIEWPORT_8:
	case PUT_DISPLAY_OPTION_VIEWPORT_9:
	case PUT_DISPLAY_OPTION_VIEWPORT_10:
	case PUT_DISPLAY_OPTION_VIEWPORT_11:
	case PUT_DISPLAY_OPTION_VIEWPORT_12:
	case PUT_DISPLAY_OPTION_EXACT:
	case PUT_DISPLAY_OPTION_POINTER:
		if (setDisplayAction(display, o, value))
			return TRUE;
	default:
		break;
	}
	return FALSE;
}

static void putDisplayInitOptions(PutDisplay * pd)
{
	CompOption *o;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT];
	o->advanced = False;
	o->name = "put_viewport";
	o->group = N_("");
	o->subGroup = N_("");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face");
	o->longDesc = N_("Move Window to a Face of the Cube.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = 0;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_1];
	o->advanced = False;
	o->name = "put_viewport_1";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to arbitrary face");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face 1");
	o->longDesc = N_("Move Window to Face 1.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_2];
	o->advanced = False;
	o->name = "put_viewport_2";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to arbitrary face");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face 2");
	o->longDesc = N_("Move Window to Face 2.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_3];
	o->advanced = False;
	o->name = "put_viewport_3";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to arbitrary face");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face 3");
	o->longDesc = N_("Move Window to Face 3.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_4];
	o->advanced = False;
	o->name = "put_viewport_4";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to arbitrary face");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face 4");
	o->longDesc = N_("Move Window to Face 4.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_5];
	o->advanced = False;
	o->name = "put_viewport_5";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to arbitrary face");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face 5");
	o->longDesc = N_("Move Window to Face 5.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_6];
	o->advanced = False;
	o->name = "put_viewport_6";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to arbitrary face");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face 6");
	o->longDesc = N_("Move Window to Face 6.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_7];
	o->advanced = False;
	o->name = "put_viewport_7";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to arbitrary face");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face 7");
	o->longDesc = N_("Move Window to Face 7.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_8];
	o->advanced = False;
	o->name = "put_viewport_8";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to arbitrary face");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face 8");
	o->longDesc = N_("Move Window to Face 8.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_9];
	o->advanced = False;
	o->name = "put_viewport_9";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to arbitrary face");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face 9");
	o->longDesc = N_("Move Window to Face 9.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_10];
	o->advanced = False;
	o->name = "put_viewport_10";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to arbitrary face");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face 10");
	o->longDesc = N_("Move Window to Face 10.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_11];
	o->advanced = False;
	o->name = "put_viewport_11";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to arbitrary face");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face 11");
	o->longDesc = N_("Move Window to Face 11.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_12];
	o->advanced = False;
	o->name = "put_viewport_12";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to arbitrary face");
	o->displayHints = "";
	o->shortDesc = N_("Put on Face 12");
	o->longDesc = N_("Move Window to Face 12.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putToViewport;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_LEFT];
	o->advanced = False;
	o->name = "put_viewport_left";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to adjacent face");
	o->displayHints = "";
	o->shortDesc = N_("Viewport Left");
	o->longDesc = N_("Move Window to the Viewport on Left.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putViewportLeft;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_RIGHT];
	o->advanced = False;
	o->name = "put_viewport_right";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to adjacent face");
	o->displayHints = "";
	o->shortDesc = N_("Viewport Right");
	o->longDesc = N_("Move Window to the Viewport on Right.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putViewportRight;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_UP];
	o->advanced = False;
	o->name = "put_viewport_up";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to adjacent face");
	o->displayHints = "";
	o->shortDesc = N_("Viewport Up");
	o->longDesc = N_("Move Window to the Viewport on Top.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putViewportUp;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_VIEWPORT_DOWN];
	o->advanced = False;
	o->name = "put_viewport_down";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to adjacent face");
	o->displayHints = "";
	o->shortDesc = N_("Viewport Down");
	o->longDesc = N_("Move Window to the Viewport on Bottom.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putViewportDown;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_RESTORE];
	o->advanced = False;
	o->name = "put_restore";
	o->group = N_("Bindings");
	o->subGroup = N_("Restore position");
	o->displayHints = "";
	o->shortDesc = N_("Restore Position");
	o->longDesc = N_("Move Window to the Last Position.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = restore;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeKey;
	o->value.action.key.modifiers = PUT_RESTORE_MODIFIERS_DEFAULT;
	o->value.action.key.keysym = XStringToKeysym(PUT_RESTORE_KEY_DEFAULT);

	o = &pd->opt[PUT_DISPLAY_OPTION_POINTER];
	o->advanced = False;
	o->name = "put_pointer";
	o->group = N_("Bindings");
	o->subGroup = N_("Put to pointer");
	o->displayHints = "";
	o->shortDesc = N_("Put Pointer");
	o->longDesc =
			N_("Move Window to the Pointer position using screen quadrant.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putPointer;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeKey;
	o->value.action.key.modifiers = PUT_POINTER_MODIFIERS_DEFAULT;
	o->value.action.key.keysym = XStringToKeysym(PUT_POINTER_KEY_DEFAULT);

	o = &pd->opt[PUT_DISPLAY_OPTION_EXACT];
	o->advanced = False;
	o->name = "put_exact";
	o->group = N_("");
	o->subGroup = N_("");
	o->displayHints = "";
	o->shortDesc = N_("Put Exact");
	o->longDesc = N_("Move Window to x, y.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putExact;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = 0;
	o->value.action.type = CompBindingTypeNone;

	o = &pd->opt[PUT_DISPLAY_OPTION_CENTER];
	o->advanced = False;
	o->name = "put_center";
	o->group = N_("Bindings");
	o->subGroup = N_("Put within face");
	o->displayHints = "";
	o->shortDesc = N_("Put Center");
	o->longDesc = N_("Move Window to the Center.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putCenter;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeKey;
	o->value.action.key.modifiers = PUT_CENTER_MODIFIERS_DEFAULT;
	o->value.action.key.keysym = XStringToKeysym(PUT_CENTER_KEY_DEFAULT);

	o = &pd->opt[PUT_DISPLAY_OPTION_LEFT];
	o->advanced = False;
	o->name = "put_left";
	o->group = N_("Bindings");
	o->subGroup = N_("Put within face");
	o->displayHints = "";
	o->shortDesc = N_("Put Left");
	o->longDesc = N_("Move Window to the Center of the Left edge.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putLeft;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeKey;
	o->value.action.key.modifiers = PUT_LEFT_MODIFIERS_DEFAULT;
	o->value.action.key.keysym = XStringToKeysym(PUT_LEFT_KEY_DEFAULT);

	o = &pd->opt[PUT_DISPLAY_OPTION_TOPLEFT];
	o->advanced = False;
	o->name = "put_top_left";
	o->group = N_("Bindings");
	o->subGroup = N_("Put within face");
	o->displayHints = "";
	o->shortDesc = N_("Put Top Left");
	o->longDesc = N_("Move Window to the Top Left corner.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putTopLeft;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeKey;
	o->value.action.key.modifiers = PUT_TOPLEFT_MODIFIERS_DEFAULT;
	o->value.action.key.keysym = XStringToKeysym(PUT_TOPLEFT_KEY_DEFAULT);

	o = &pd->opt[PUT_DISPLAY_OPTION_TOP];
	o->advanced = False;
	o->name = "put_top";
	o->group = N_("Bindings");
	o->subGroup = N_("Put within face");
	o->displayHints = "";
	o->shortDesc = N_("Put Top");
	o->longDesc = N_("Move Window to the Center of the Top edge.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putTop;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeKey;
	o->value.action.key.modifiers = PUT_TOP_MODIFIERS_DEFAULT;
	o->value.action.key.keysym = XStringToKeysym(PUT_TOP_KEY_DEFAULT);

	o = &pd->opt[PUT_DISPLAY_OPTION_TOPRIGHT];
	o->advanced = False;
	o->name = "put_top_right";
	o->group = N_("Bindings");
	o->subGroup = N_("Put within face");
	o->displayHints = "";
	o->shortDesc = N_("Put Top Right");
	o->longDesc = N_("Move Window to the Top Right corner.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putTopRight;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeKey;
	o->value.action.key.modifiers = PUT_TOPRIGHT_MODIFIERS_DEFAULT;
	o->value.action.key.keysym = XStringToKeysym(PUT_TOPRIGHT_KEY_DEFAULT);

	o = &pd->opt[PUT_DISPLAY_OPTION_RIGHT];
	o->advanced = False;
	o->name = "put_right";
	o->group = N_("Bindings");
	o->subGroup = N_("Put within face");
	o->displayHints = "";
	o->shortDesc = N_("Put Right");
	o->longDesc = N_("Move Window to the Center of the Right edge.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putRight;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeKey;
	o->value.action.key.modifiers = PUT_RIGHT_MODIFIERS_DEFAULT;
	o->value.action.key.keysym = XStringToKeysym(PUT_RIGHT_KEY_DEFAULT);

	o = &pd->opt[PUT_DISPLAY_OPTION_BOTTOMRIGHT];
	o->advanced = False;
	o->name = "put_bottom_right";
	o->group = N_("Bindings");
	o->subGroup = N_("Put within face");
	o->displayHints = "";
	o->shortDesc = N_("Put Bottom Right");
	o->longDesc = N_("Move Window to the Bottom Right corner.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putBottomRight;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeKey;
	o->value.action.key.modifiers = PUT_BOTTOMRIGHT_MODIFIERS_DEFAULT;
	o->value.action.key.keysym = XStringToKeysym(PUT_BOTTOMRIGHT_KEY_DEFAULT);

	o = &pd->opt[PUT_DISPLAY_OPTION_BOTTOM];
	o->advanced = False;
	o->name = "put_bottom";
	o->group = N_("Bindings");
	o->subGroup = N_("Put within face");
	o->displayHints = "";
	o->shortDesc = N_("Put Bottom");
	o->longDesc = N_("Move Window to the Center of the Bottom edge.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putBottom;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeKey;
	o->value.action.key.modifiers = PUT_BOTTOM_MODIFIERS_DEFAULT;
	o->value.action.key.keysym = XStringToKeysym(PUT_BOTTOM_KEY_DEFAULT);

	o = &pd->opt[PUT_DISPLAY_OPTION_BOTTOMLEFT];
	o->advanced = False;
	o->name = "put_bottom_left";
	o->group = N_("Bindings");
	o->subGroup = N_("Put within face");
	o->displayHints = "";
	o->shortDesc = N_("Put Bottom Left");
	o->longDesc = N_("Move Window to the Bottom Left corner.");
	o->type = CompOptionTypeAction;
	o->value.action.initiate = putBottomLeft;
	o->value.action.terminate = 0;
	o->value.action.bell = FALSE;
	o->value.action.edgeMask = 0;
	o->value.action.state = CompActionStateInitKey;
	o->value.action.state |= CompActionStateInitButton;
	o->value.action.type = CompBindingTypeKey;
	o->value.action.key.modifiers = PUT_BOTTOMLEFT_MODIFIERS_DEFAULT;
	o->value.action.key.keysym = XStringToKeysym(PUT_BOTTOMLEFT_KEY_DEFAULT);
}

static CompOption *putGetDisplayOptions(CompDisplay * display, int *count)
{
	if (display)
	{
		PUT_DISPLAY(display);
		*count = NUM_OPTIONS(pd);
		return pd->opt;
	}
	else
	{
		PutDisplay *pd = malloc(sizeof(PutDisplay));

		putDisplayInitOptions(pd);
		*count = NUM_OPTIONS(pd);
		return pd->opt;
	}
}

static Bool putInitDisplay(CompPlugin * p, CompDisplay * d)
{
	PutDisplay *pd;

	pd = malloc(sizeof(PutDisplay));
	if (!pd)
		return FALSE;

	pd->screenPrivateIndex = allocateScreenPrivateIndex(d);
	if (pd->screenPrivateIndex < 0)
	{
		free(pd);
		return FALSE;
	}

	/* custom atom for client events */
	pd->berylPutWindowAtom = XInternAtom(d->display, "_BERYL_PUT_WINDOW", 0);

	putDisplayInitOptions(pd);
	WRAP(pd, d, handleEvent, putHandleEvent);
	d->privates[displayPrivateIndex].ptr = pd;

	return TRUE;
}

static void putFiniDisplay(CompPlugin * p, CompDisplay * d)
{
	PUT_DISPLAY(d);
	freeScreenPrivateIndex(d, pd->screenPrivateIndex);
	UNWRAP(pd, d, handleEvent);
	free(pd);
}

static Bool putInitScreen(CompPlugin * p, CompScreen * s)
{
	PutScreen *ps;

	PUT_DISPLAY(s->display);

	ps = malloc(sizeof(PutScreen));
	if (!ps)
		return FALSE;

	ps->windowPrivateIndex = allocateWindowPrivateIndex(s);
	if (ps->windowPrivateIndex < 0)
	{
		free(ps);
		return FALSE;
	}

	/* initialize variables
	 * bad stuff happens if we don't do this
	 */
	ps->speed = PUT_SPEED_DEFAULT;
	ps->timestep = PUT_TIMESTEP_DEFAULT;
	ps->moreAdjust = FALSE;
	ps->padLeft = PUT_LEFT_PAD_DEFAULT;
	ps->padTop = PUT_TOP_PAD_DEFAULT;
	ps->padRight = PUT_RIGHT_PAD_DEFAULT;
	ps->padBottom = PUT_BOTTOM_PAD_DEFAULT;
	ps->vpMoving = FALSE;
	ps->unfocusWindow = PUT_UNFOCUS_WINDOW_DEFAULT;
	ps->windowcenter = PUT_WINDOW_CENTER_DEFAULT;
	ps->avoidoffscreen = PUT_AVOID_OFFSCREEN_DEFAULT;
	ps->current = NULL;
	ps->grabIndex = 0;

	/* Initialize the screen options
	 * again, bad stuff if we forget
	 */
	putScreenInitOptions(ps);

	/* add the screen actions */
	addScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_POINTER].value.action);
	addScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_RESTORE].value.action);
	addScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_CENTER].value.action);
	addScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_LEFT].value.action);
	addScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_TOPLEFT].value.action);
	addScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_TOP].value.action);
	addScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_TOPRIGHT].value.action);
	addScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_RIGHT].value.action);
	addScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_BOTTOMRIGHT].value.action);
	addScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_BOTTOM].value.action);
	addScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_BOTTOMLEFT].value.action);

	/* wrap the overloaded functions */
	WRAP(ps, s, preparePaintScreen, putPreparePaintScreen);
	WRAP(ps, s, donePaintScreen, putDonePaintScreen);
	WRAP(ps, s, paintScreen, putPaintScreen);
	WRAP(ps, s, paintWindow, putPaintWindow);

	s->privates[pd->screenPrivateIndex].ptr = ps;
	return TRUE;
}

static void putFiniScreen(CompPlugin * p, CompScreen * s)
{
	PUT_SCREEN(s);
	PUT_DISPLAY(s->display);
	freeWindowPrivateIndex(s, ps->windowPrivateIndex);
	UNWRAP(ps, s, preparePaintScreen);
	UNWRAP(ps, s, donePaintScreen);
	UNWRAP(ps, s, paintScreen);
	UNWRAP(ps, s, paintWindow);

	removeScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_POINTER].value.action);
	removeScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_RESTORE].value.action);
	removeScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_CENTER].value.action);
	removeScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_LEFT].value.action);
	removeScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_TOPLEFT].value.action);
	removeScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_TOP].value.action);
	removeScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_TOPRIGHT].value.action);
	removeScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_RIGHT].value.action);
	removeScreenAction(s,
					   &pd->opt[PUT_DISPLAY_OPTION_BOTTOMRIGHT].value.action);
	removeScreenAction(s, &pd->opt[PUT_DISPLAY_OPTION_BOTTOM].value.action);
	removeScreenAction(s,
					   &pd->opt[PUT_DISPLAY_OPTION_BOTTOMLEFT].value.action);
	free(ps);
}

static Bool putInitWindow(CompPlugin * p, CompWindow * w)
{
	PutWindow *pw;

	PUT_SCREEN(w->screen);

	pw = malloc(sizeof(PutWindow));
	if (!pw)
		return FALSE;

	/* initialize variables
	 * I don't need to repeat it
	 */
	pw->tx = pw->ty = pw->xVelocity = pw->yVelocity = 0.0f;
	pw->dx = pw->dy = 0;
	pw->lastX = pw->x = w->serverX;
	pw->lastY = pw->y = w->serverY;
	pw->adjust = FALSE;

	w->privates[ps->windowPrivateIndex].ptr = pw;

	return TRUE;
}

static void putFiniWindow(CompPlugin * p, CompWindow * w)
{
	PUT_WINDOW(w);
	free(pw);
}

static Bool putInit(CompPlugin * p)
{
	displayPrivateIndex = allocateDisplayPrivateIndex();
	if (displayPrivateIndex < 0)
		return FALSE;

	return TRUE;
}

static void putFini(CompPlugin * p)
{
	if (displayPrivateIndex >= 0)
		freeDisplayPrivateIndex(displayPrivateIndex);
}

/*
 * vTable tells the dl
 * what we offer
 */
CompPluginVTable putVTable = {
	"put",
	N_("Put"),
	N_("Put window"),
	putInit,
	putFini,
	putInitDisplay,
	putFiniDisplay,
	putInitScreen,
	putFiniScreen,
	putInitWindow,
	putFiniWindow,
	putGetDisplayOptions,
	putSetDisplayOption,
	putGetScreenOptions,
	putSetScreenOption,
	0,
	0,
	0,
	0,
	BERYL_ABI_INFO,
	"beryl-plugins",
	"wm",
	0,
	0,
	False,
};

CompPluginVTable *getCompPluginInfo(void)
{
	return &putVTable;
}


syntax highlighted by Code2HTML, v. 0.9.1