Newer
Older
x-wm / x-wm.c
@Andreas Jaggi Andreas Jaggi on 25 Jun 2007 6 KB Customized for NovaWave DFG.
/* $Id$ */
/*
 * Copyright (c) 2007 Andreas Jaggi <andreas.jaggi@waterwave.ch>
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "x-wm.h"
#include "client.h"

Display* display;
int screen;
Window root;
Window focus;
Atom wm_delete_window;
Atom wm_protocols;
int clientcounter = 0;
int quit = 0;
char* startscript = NULL;

void loop();
void handle_crossing(XCrossingEvent* ev);
void handle_create(XCreateWindowEvent* ev);
void handle_destroy(XDestroyWindowEvent* ev);
void close_window(Window w);
void maximize_client(Client *c);

int main ( int argc, char* argv[] ) {
	Client *c;

	Window dw1, dw2;
	Window* existing_windows;

	int i, win_count;
	int r = -1;
	int status;

	XSetWindowAttributes attr;

	while ( (r = getopt(argc, argv, "hlvs:")) != -1 ) {
		switch ( r ) {
			case 'h':
				usage();
				exit(0);
			case 'l':
				license();
				exit(0);
			case 'v':
				version();
				exit(0);
			case 's':
				startscript = optarg;
				break;
			default:
				usage();
				exit(1);
		}
	}

	fprintf(stdout, "starting x-wm...\n");

	if ( startscript != NULL ) {
		fprintf(stdout, "x-wm: running startscript: %s...\n", startscript);
		switch ( fork() ) {
			case 0:
				execlp(startscript,startscript,0);
			case -1:
				fprintf(stderr, "x-wm: could not fork()!\n");
			default:
				wait(&status);

				if ( WIFEXITED(status) ) {
					fprintf(stderr, "x-wm: startscript (%s) ended with exit(%d)\n", startscript, WEXITSTATUS(status));
				}
				if ( WIFSIGNALED(status) ) {
					fprintf(stderr, "x-wm: startscript (%s) received signal %d\n", startscript, WTERMSIG(status));
				}
		}
	}

	if ( !(display = XOpenDisplay(NULL)) ) {
		fprintf(stderr, "x-wm: cannot open display\n");
		exit(1);
	}

	screen = DefaultScreen(display);
	root = RootWindow(display, screen);

	attr.event_mask = 0
		//| SubstructureRedirectMask
		//| SubstructureNotifyMask
		| StructureNotifyMask
		//| PropertyChangeMask
		| EnterWindowMask
		//| LeaveWindowMask
		//| ButtonPressMask
		//| ButtonReleaseMask
		//| KeyPressMask
		//| KeyReleaseMask
		//| FocusChangeMask
		//| PointerMotionMask
		//| PointerMotionHintMask
		//| Button1MotionMask
		//| Button2MotionMask
		//| Button3MotionMask
		//| Button4MotionMask
		//| Button5MotionMask
		//| ButtonMotionMask
		;

	XChangeWindowAttributes(display, root, CWEventMask, &attr);

	wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
	wm_protocols = XInternAtom(display, "WM_PROTOCOLS", False);

	init_clients();

	XQueryTree(display, root, &dw1, &dw2, &existing_windows, &win_count);
	fprintf(stderr, "x-wm: win_count = %d\n", win_count);
	for ( i = 0; i < win_count; i++ ) {
		if ( existing_windows[i] != root ) {
			clientcounter++;
			c = create_client(existing_windows[i]);
			maximize_client(c);
		}
	}
	XFree(existing_windows);

	fprintf(stderr, "x-wm: clientcount = %d\n", clientcounter);

	loop();

	exit(0);
}

void loop ( ) {
	XEvent ev;
	while ( !quit ) {
		XNextEvent(display, &ev);

		switch ( ev.type ) {
			case EnterNotify:
				handle_crossing(&(ev.xcrossing));
				break;
			case CreateNotify:
				handle_create(&(ev.xcreatewindow));
				break;
			case DestroyNotify:
				handle_destroy(&(ev.xdestroywindow));
				break;
			default:
				fprintf(stderr, "x-wm: received XEvent of unknown type %d\n", ev.type);
		}
	}
}

void handle_destroy( XDestroyWindowEvent* ev ) {
	fprintf(stdout, "x-wm: received XDestroyWindowEvent event\n");
	clientcounter--;
	fprintf(stderr, "x-wm: clientcounter: %d\n", clientcounter);
	destroy_client(ev->window);

	if ( ev->window == root ) {
		fprintf(stderr, "x-wm: root window destroyed, quitting...\n");
		quit = 1;
	}

	if ( clientcounter <= 0 ) {
		fprintf(stderr, "x-wm: clientcounter <= 0 (%d), quitting...\n", clientcounter);
		quit = 1;
	}
}

void handle_create ( XCreateWindowEvent* ev ) {
	Client *c;

	fprintf(stdout, "x-wm: received XCreateWindowEvent event\n");

	if ( NULL == (c = find_client(ev->window)) ) {
		c = create_client(ev->window);
	}
	
	maximize_client(c);

	XAddToSaveSet(display, ev->window);
	XRaiseWindow(display, ev->window);
	XSetInputFocus(display, ev->window, RevertToPointerRoot, CurrentTime);

	clientcounter++;
	fprintf(stderr, "x-wm: clientcounter: %d\n", clientcounter);
}

void handle_crossing ( XCrossingEvent* ev ) {
	fprintf(stdout, "x-wm: received XCrossingEvent event: state %d\n", ev->state);
	if ( ev->type == EnterNotify ) {
		XUngrabButton(display, Button1, 0, root);

		fprintf(stdout, "x-wm: received EnterNotify event: state %d\n", ev->state);
		XSetInputFocus(display, ev->window, RevertToPointerRoot, ev->time);
	}

	if ( ev->type == LeaveNotify ) {
		fprintf(stdout, "x-wm: received LeaveNotify event: state %d\n", ev->state);
		XGrabButton(display, Button1, 0, root, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
	}
}

void maximize_client ( Client *c ) {
	XMoveResizeWindow(display, c->window, 0, 0, DisplayWidth(display, screen), DisplayHeight(display, screen));
}

void close_window ( Window w ) {
	XEvent ev;
	int protocols_count, i;
	Atom* protocols;

	if ( XGetWMProtocols(display, w, &protocols, &protocols_count) ) {
		for ( i = 0; i < protocols_count; i++ ) {
			if ( protocols[i] == wm_delete_window ) {
				ev.type = ClientMessage;
				ev.xclient.window = w;
				ev.xclient.message_type = wm_protocols;
				ev.xclient.format = 32;
				ev.xclient.data.l[0] = wm_delete_window;
				ev.xclient.data.l[1] = CurrentTime;

				XSendEvent(display, w, False, NoEventMask, &ev);
				XFree(protocols);
				return;
			}
		}

		if ( protocols ) {
			XFree(protocols);
		}
	}

	XKillClient(display, w);
}