/* $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);
}