/*
 * BadWM - minimalistic window manager for the X Window System
 * Copyright (C) Robert Annessi <robert@annessi.at>
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "include/BadWM.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <X11/cursorfont.h>
#include <stdio.h>
#include "include/config.h"

Display		*dpy;
int 		num_screens;
ScreenInfo	*screens;
ScreenInfo	*current_screen;
Client		*current = NULL;
Window		initialising = None;
XFontStruct	*font;
Client		*head_client;
Atom		xa_wm_state;
Atom		xa_wm_change_state;
Atom		xa_wm_protos;
Atom		xa_wm_delete;
Atom		xa_wm_cmapwins;
Cursor          arrow_curs;
Cursor          move_curs;
Cursor          resize_cursors[8];
const char	*opt_display = "";
const char	*opt_font = DEF_FONT;
const char	**opt_term = NULL;
int		opt_bw = DEF_BW;
int		vdesk = KEY_TO_VDESK(XK_1);
int		have_shape, shape_event;
int		quitting = 0;
unsigned int numlockmask = 0;
static void *xmalloc(size_t size);

static void *xmalloc(size_t size) {
	       void *ptr = malloc(size);
	       if (!ptr) {
               exit(1);
       }
       return ptr;
}

int main(int argc, char *argv[]) {
	struct sigaction act;
	XEvent ev;
	int c; 
	int i;

	initstr();

	while(1)
	{
		#ifdef DEBUG
			c = getopt(argc, argv, "d:vh");
		#else
			c = getopt(argc, argv, "vh");
		#endif	
		
		if (c == -1)
			break;

		switch(c)
		{
			#ifdef DEBUG
				case 'd':
					config.global->debug = is_int(optarg);
					break;
			#endif
			case 'v':
				printf(PACKAGE_NAME" Version "VERSION"\n");
				exit(0);
				break;
			case 'h':
				printf("See the manpage. man 1 "PACKAGE_NAME"\n");
				exit(0);
				break;
			default:
				printf("-h for more info!\n");
				exit(1);
				break;
		}
	}

	act.sa_handler = handle_signal;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
	sigaction(SIGHUP, &act, NULL);

	setconf();
	setup_display();
	have_shape = XShapeQueryExtension(dpy, &shape_event, &i);

	/* main event loop here */
	for (;;) {
		XNextEvent(dpy, &ev);
		switch (ev.type) {
			case KeyPress:
				handle_key_event(&ev.xkey); break;
			case ButtonPress:
				handle_button_event(&ev.xbutton); break;
			case ConfigureRequest:
				handle_configure_request(&ev.xconfigurerequest); break;
			case MapRequest:
				handle_map_request(&ev.xmaprequest); break;
			case ClientMessage:
				handle_client_message(&ev.xclient); break;
			case EnterNotify:
				handle_enter_event(&ev.xcrossing); break;
			case PropertyNotify:
				handle_property_change(&ev.xproperty); break;
			case UnmapNotify:
				handle_unmap_event(&ev.xunmap); break;
			default:
				if (have_shape && ev.type == shape_event) {
					handle_shape_event((XShapeEvent *)&ev);
				}
				break;
		}
	}
	return 1;
}

void setup_display() {
	XGCValues gv;
	XSetWindowAttributes attr;
	XColor dummy;
	XModifierKeymap *modmap;
	KeySym *keysym;

	/* used in scanning windows (XQueryTree) */
	unsigned int i, j, nwins;
	Window dw1, dw2, *wins;
	XWindowAttributes winattr;

	dpy = XOpenDisplay(opt_display);
	if (!dpy) { 
		fprintf(stderr, "can't open display %s\n", opt_display);
		exit(2);
	}
	XSetErrorHandler(handle_xerror);

	xa_wm_state = XInternAtom(dpy, "WM_STATE", False);
	xa_wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False);
	xa_wm_protos = XInternAtom(dpy, "WM_PROTOCOLS", False);
	xa_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);

	font = XLoadQueryFont(dpy, opt_font);
	if (!font) font = XLoadQueryFont(dpy, DEF_FONT);

	arrow_curs = XCreateFontCursor(dpy, XC_top_left_arrow);
	move_curs = XCreateFontCursor(dpy, XC_fleur);

        resize_cursors[NorthWest] = XCreateFontCursor(dpy,XC_top_left_corner);
        resize_cursors[North] = XCreateFontCursor(dpy,XC_top_side);
        resize_cursors[NorthEast] = XCreateFontCursor(dpy,XC_top_right_corner);
        resize_cursors[East] = XCreateFontCursor(dpy,XC_right_side);
        resize_cursors[SouthEast] = XCreateFontCursor(dpy,XC_bottom_right_corner);
        resize_cursors[South] = XCreateFontCursor(dpy,XC_bottom_side);
        resize_cursors[SouthWest] = XCreateFontCursor(dpy,XC_bottom_left_corner);
        resize_cursors[West] = XCreateFontCursor(dpy,XC_left_side);

	/* find out which modifier is NumLock - we'll use this when grabbing
	 * every combination of modifiers we can think of */
	modmap = XGetModifierMapping(dpy);
	for (i = 0; i < 8; i++) {
		for (j = 0; j < modmap->max_keypermod; j++) {
			if (modmap->modifiermap[i*modmap->max_keypermod+j] == XKeysymToKeycode(dpy, XK_Num_Lock)) {
				numlockmask = (1<<i);
				#ifdef DEBUG
                                	bad_debug(1,"setup_display() : XK_Num_Lock is (1<<0x%02x)\n", i); 
				#endif
			}
		}
	}
	XFreeModifiermap(modmap);

	/* set up GC parameters - same for each screen */
	gv.function = GXinvert;
	gv.subwindow_mode = IncludeInferiors;
	gv.line_width = opt_bw;
	gv.font = font->fid;

	/* set up root window attributes - same for each screen */
	attr.event_mask = ChildMask | PropertyChangeMask | EnterWindowMask | LeaveWindowMask
		| ButtonMask
		;

	/* now set up each screen in turn */
	num_screens = ScreenCount(dpy);
	screens = (ScreenInfo *)xmalloc(num_screens * sizeof(ScreenInfo));
	for (i = 0; i < num_screens; i++) {
		char *ds, *colon, *dot;
		ds = DisplayString(dpy);
		/* set up DISPLAY environment variable to use */
		colon = rindex(ds, ':');
		if (colon && num_screens > 1) {
			screens[i].display = (char *)xmalloc(14 + strlen(ds));
			strcpy(screens[i].display, "DISPLAY=");
			strcat(screens[i].display, ds);
			colon = rindex(screens[i].display, ':');
			dot = index(colon, '.');
			if (!dot)
				dot = colon + strlen(colon);
			snprintf(dot, 5, ".%d", i);
		} else
			screens[i].display = NULL;

		screens[i].screen = i;
		screens[i].root = RootWindow(dpy, i);

		XAllocNamedColor(dpy, DefaultColormap(dpy, i), config.theme->fgcolor, &screens[i].fg, &dummy);
		XAllocNamedColor(dpy, DefaultColormap(dpy, i), config.theme->bgcolor, &screens[i].bg, &dummy);
		XAllocNamedColor(dpy, DefaultColormap(dpy, i), config.theme->fxcolor, &screens[i].fc, &dummy);

		screens[i].invert_gc = XCreateGC(dpy, screens[i].root, GCFunction | GCSubwindowMode | GCLineWidth | GCFont, &gv);

		XChangeWindowAttributes(dpy, screens[i].root, CWEventMask, &attr);
		grab_keysym(screens[i].root, Mod1Mask, *keysym);

		#ifdef DEBUG
			/* scan all the windows on this screen */
        	        bad_debug(1,"main:XQueryTree()\n");
		#endif
		XQueryTree(dpy, screens[i].root, &dw1, &dw2, &wins, &nwins);
		#ifdef DEBUG
			bad_debug(1,"%d windows\n", nwins);
		#endif
		for (j = 0; j < nwins; j++) {
			XGetWindowAttributes(dpy, wins[j], &winattr);
			if (!winattr.override_redirect && winattr.map_state == IsViewable)
				make_new_client(wins[j], &screens[i]);
		}
		XFree(wins);
		XDefineCursor(dpy,screens[i].root,arrow_curs);
	}
	current_screen = find_screen(DefaultScreen(dpy));
}


syntax highlighted by Code2HTML, v. 0.9.1