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