#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include "settings.h"

/* readability stuff */

#define STICKY 0	/* Desktop number for sticky clients */
#define KEY_TO_VDESK( key ) ( ( key ) - XK_1 + 1 )

#define RAISE		1
#define NO_RAISE	0	/* for unhide() */

typedef enum { NorthWest, North, NorthEast, East, SouthEast, South, SouthWest,
              West } ResizeDir;


/* some coding shorthand */

#define ChildMask	(SubstructureRedirectMask|SubstructureNotifyMask)
#define ButtonMask	(ButtonPressMask|ButtonReleaseMask)
#define MouseMask	(ButtonMask|PointerMotionMask)

#define grab_pointer(w, mask, curs) \
	(XGrabPointer(dpy, w, False, mask, GrabModeAsync, GrabModeAsync, \
	None, curs, CurrentTime) == GrabSuccess)
#define grab_keysym(w, mask, keysym) \
	XGrabKey(dpy, XKeysymToKeycode(dpy, keysym), mask, w, True, \
			GrabModeAsync, GrabModeAsync); \
	XGrabKey(dpy, XKeysymToKeycode(dpy, keysym), LockMask|mask, w, True, \
			GrabModeAsync, GrabModeAsync); \
	if (numlockmask) { \
		XGrabKey(dpy, XKeysymToKeycode(dpy, keysym), numlockmask|mask, \
				w, True, GrabModeAsync, GrabModeAsync); \
		XGrabKey(dpy, XKeysymToKeycode(dpy, keysym), \
				numlockmask|LockMask|mask, w, True, \
				GrabModeAsync, GrabModeAsync); \
	}
#define grab_button(w, mask, button) \
	XGrabButton(dpy, button, mask, w, False, ButtonMask, \
			GrabModeAsync, GrabModeSync, None, None); \
	XGrabButton(dpy, button, LockMask|mask, w, False, ButtonMask, \
			GrabModeAsync, GrabModeSync, None, None); \
	if (numlockmask) { \
		XGrabButton(dpy, button, numlockmask|mask, w, False, \
				ButtonMask, GrabModeAsync, GrabModeSync, \
				None, None); \
		XGrabButton(dpy, button, numlockmask|LockMask|mask, w, False, \
				ButtonMask, GrabModeAsync, GrabModeSync, \
				None, None); \
	}
#define setmouse(w, x, y) \
	XWarpPointer(dpy, None, w, 0, 0, 0, 0, x, y)
#define gravitate(c) \
	change_gravity(c, 1)
#define ungravitate(c) \
	change_gravity(c, -1)

/* screen structure */

typedef struct ScreenInfo ScreenInfo;

struct ScreenInfo {
	int screen;
	Window root;
	Colormap def_cmap;
	GC invert_gc;
	XColor fg, bg, fc;
	char *display;
};

/* client structure */

typedef struct Client Client;

struct Client {
	Client	*next;
	Window	window;
	Window	parent;
	ScreenInfo	*screen;

	XSizeHints	*size;
	int		ignore_unmap;

	int		x, y, width, height;
	int		oldx, oldy, oldw, oldh;  /* used when maximising */
	int		border;
	int		vdesk;
};

/* declarations for global variables in main.c */

extern Display		*dpy;
extern int		num_screens;
extern ScreenInfo	*screens;
extern ScreenInfo	*current_screen;
extern Client		*current;
extern Window		initialising;
extern XFontStruct	*font;
extern Client		*head_client;
extern Atom		xa_wm_state;
extern Atom		xa_wm_change_state;
extern Atom		xa_wm_protos;
extern Atom		xa_wm_delete;
extern Atom		xa_wm_cmapwins;
extern Cursor           arrow_curs;
extern Cursor		move_curs;
extern Cursor           resize_cursors[]; // indexed by dir
extern const char	*opt_display;
extern const char	*opt_font;
extern const char	*opt_fg;
extern const char	*opt_bg;
extern const char	**opt_term;
extern int		opt_bw;
extern const char	*opt_fc;
extern int		vdesk;
extern int		opt_snap;
extern int		quitting;
extern unsigned int numlockmask;

/* client.c */

Client *find_client(Window w);
int wm_state(Client *c);
void change_gravity(Client *c, int multiplier);
void remove_client(Client *c);
void send_wm_delete(Client *c);
void set_wm_state(Client *c, int state);
void client_update_current(Client *c, Client *newcurrent);
void client_to_front(Client *c);
void focus_client( Client *c );

/* events.c */

void handle_key_event(XKeyEvent *e);
void handle_button_event(XButtonEvent *e);
void handle_configure_request(XConfigureRequestEvent *e);
void handle_enter_event(XCrossingEvent *e);
void handle_map_request(XMapRequestEvent *e);
void handle_property_change(XPropertyEvent *e);
void handle_unmap_event(XUnmapEvent *e);

/* main.c */

int main(int argc, char *argv[]);
void setup_display(void);

/* void do_event_loop(void); */
int handle_xerror(Display *dsply, XErrorEvent *e);
int ignore_xerror(Display *dsply, XErrorEvent *e);
void dump_clients(void);
//void spawn(const char *const cmd[]);
void spawn(const char **cmd);
void handle_signal(int signo);

/* new.c */

void init_position(Client *c);
void make_new_client(Window w, ScreenInfo *s);
void reparent(Client *c);

/* screen.c */

void drag(Client *c);
void draw_outline(Client *c);
void get_mouse_position(int *x, int *y, Window root);
void move(Client *c, int set);
void recalculate_sweep(Client *c, int x1, int y1, int x2, int y2, int westw, 
                      int northw);
void resize(Client *c, int set);
void maximise(Client *c);
void maximise_vert(Client *c);
void maximise_horiz(Client *c);
void sweep(Client *c);
void unhide(Client *c, int raise, int bringtofront);
void next(void);
void hide(Client *c);
void switch_vdesk(int v);
ScreenInfo *find_screen(Window root);
int wl, wu, snap_pixel;
//Window dummy;
