From c938ad029d5530670e657aac56ae9bb4e2045c89 Mon Sep 17 00:00:00 2001
From: kramm <kramm>
Date: Sun, 3 Jun 2007 09:17:22 +0000
Subject: [PATCH] gfx gui abstraction

---
 lib/gfxwindow.c       |   27 ++
 lib/gfxwindow.h       |   73 +++++
 lib/gfxwindow_unix.c  |  850 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/gfxwindow_win32.c |  430 +++++++++++++++++++++++++
 4 files changed, 1380 insertions(+)
 create mode 100644 lib/gfxwindow.c
 create mode 100644 lib/gfxwindow.h
 create mode 100644 lib/gfxwindow_unix.c
 create mode 100644 lib/gfxwindow_win32.c

diff --git a/lib/gfxwindow.c b/lib/gfxwindow.c
new file mode 100644
index 0000000..42308e0
--- /dev/null
+++ b/lib/gfxwindow.c
@@ -0,0 +1,27 @@
+/* gfxwindow.h 
+
+   Simple GUI abstraction.
+
+   Part of the swftools package.
+
+   Copyright (c) 2005 Matthias Kramm <kramm@quiss.org> 
+
+   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 */
+
+#ifdef WIN32
+#include "gfxwindow_win32.c"
+#else
+#include "gfxwindow_unix.c"
+#endif
diff --git a/lib/gfxwindow.h b/lib/gfxwindow.h
new file mode 100644
index 0000000..ba88639
--- /dev/null
+++ b/lib/gfxwindow.h
@@ -0,0 +1,73 @@
+/* gfxwindow.h 
+
+   Simple GUI abstraction.
+
+   Part of the swftools package.
+
+   Copyright (c) 2005 Matthias Kramm <kramm@quiss.org> 
+
+   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 */
+
+#ifndef __gfxwindow_h__
+#define __gfxwindow_h__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GFXEVENT_NOTHING 0
+
+#define GFXEVENT_KEY 4
+#define GFXEVENT_KEYPRESS 4
+#define GFXEVENT_KEYRELEASE 5
+
+#define GFXEVENT_MOUSEPRESS 8
+#define GFXEVENT_MOUSERELEASE 9
+#define GFXEVENT_MOUSEMOVE 10
+#define GFXEVENT_MOUSEENTER 11
+#define GFXEVENT_MOUSELEAVE 12
+
+#define GFXEVENT_DESTROY 16
+
+typedef struct _gfxevent
+{
+    void * internal;
+    int type;
+    int key; //if type == KEY
+    int x,y; //if type == MOUSEMOVED
+    int button; //if type = MOUSEPRESSED/RELEASED
+} gfxevent_t;
+
+typedef struct _gfxwindow
+{
+    void * internal;
+    unsigned char* currentscr;
+    unsigned char* lastscr;
+    int width;
+    int height;
+    void (*flippage)(struct _gfxwindow*win);
+    void (*move)(struct _gfxwindow*win,int x, int y);
+    void (*resize)(struct _gfxwindow*win,int width, int height);
+    gfxevent_t (*getEvent)(struct _gfxwindow*win);
+    void (*destroy)(struct _gfxwindow*win);
+} gfxwindow_t;
+
+gfxwindow_t* gfxwindow_new(int width, int height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/gfxwindow_unix.c b/lib/gfxwindow_unix.c
new file mode 100644
index 0000000..8573edf
--- /dev/null
+++ b/lib/gfxwindow_unix.c
@@ -0,0 +1,850 @@
+/* gfxwindow.h 
+
+   Simple GUI abstraction- Unix implementation
+
+   Part of the swftools package.
+
+   Copyright (c) 2005 Matthias Kramm <kramm@quiss.org> 
+
+   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 <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <memory.h>
+#include <unistd.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/xpm.h>
+#include <X11/Xthreads.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/XShm.h>
+#include "gfxwindow.h"
+#include "types.h"
+
+#define USE_SHM 1
+#define USE_PIXMAP 1 // use pixmap instead of ximage for off-screen rendering
+
+#define initMutex(mutex) {pthread_mutex_init(mutex, 0);}
+#define destroyMutex(mutex) {pthread_mutex_destroy((mutex));}
+#define lockMutex(mutex) pthread_mutex_lock(mutex)
+#define unlockMutex(mutex) pthread_mutex_unlock(mutex)
+
+typedef struct _queue
+{
+    char* data;
+    int readpos;
+    int writepos;
+    int number;
+    int size;
+    int nmemb;
+    pthread_mutex_t mutex;
+} queue_t;
+
+
+queue_t* queue_init(int size, int nmemb)
+{
+    queue_t* queue = malloc(sizeof(queue_t));
+    queue->data = (char*)malloc(size * nmemb);
+    queue->size = size;
+    queue->nmemb = nmemb;
+    queue->readpos = 0;
+    queue->writepos = 0;
+    queue->number = 0;
+    initMutex(&queue->mutex);
+    return queue;
+}
+
+void queue_destroy(queue_t*queue)
+{
+    free(queue->data);queue->data = 0;
+    destroyMutex(&queue->mutex);
+    memset(queue, 0, sizeof(queue_t));
+}
+
+int queue_put(queue_t*queue, void*data)
+{
+    int tmp = queue->writepos+1;
+    tmp%=queue->nmemb;
+
+    lockMutex(&queue->mutex);
+    if(tmp==queue->readpos) {
+	unlockMutex(&queue->mutex);
+	return 0;
+    }
+    memcpy(&queue->data[queue->writepos*queue->size], data, queue->size);
+    queue->writepos = tmp;
+    queue->number++;
+    unlockMutex(&queue->mutex);
+    return 1;
+}
+
+int queue_get(queue_t*queue, void*data)
+{
+    lockMutex(&queue->mutex);
+    if(queue->writepos == queue->readpos) {
+	unlockMutex(&queue->mutex);
+	return 0;
+    }
+    memcpy(data, &queue->data[queue->readpos*queue->size], queue->size);
+    queue->readpos++;
+    queue->readpos %= queue->nmemb;
+    queue->number--;
+    unlockMutex(&queue->mutex);
+    return 1;
+}
+
+void queue_flush(queue_t*queue)
+{
+    lockMutex(&queue->mutex);
+    queue->number = 0;
+    queue->readpos = 0;
+    queue->writepos = 0;
+    unlockMutex(&queue->mutex);
+}
+
+int queue_num(queue_t*queue)
+{
+    return queue->number;
+}
+
+static int initializexwindows();
+
+struct _QXWindow;
+struct X
+{
+    char isnative24;
+    char isnative16;
+    char isnative8;
+    int bpp;
+    int bypp;
+    Atom atom_wm;
+    Atom atom_wmdelete;
+
+    int rootsizex;
+    int rootsizey;
+
+    Display *d;
+    Window root;
+    int s;
+    Visual*v;
+
+    char running;
+    pthread_t eventhandler;
+    pthread_mutex_t xmutex;
+
+    struct _QXWindow*windowring;
+
+    int stopall;
+    Colormap cmap;
+    U32 white;
+    U32 black;
+}; 
+static struct X X;
+
+static int initialized = 0;
+   
+void destroyX() {
+    X.stopall=1;
+    if(X.running)
+      pthread_cancel(X.eventhandler);
+    if(X.d)
+      XCloseDisplay(X.d);
+    pthread_mutex_destroy(&X.xmutex);
+}
+
+typedef struct _QXWindow {
+    struct _QXWindow*next;
+    struct _QXWindow*prev;
+
+    XWMHints *xwmh;
+    XClassHint *xch;
+
+    GC gc;
+    //XFontStruct *xfs;
+
+    XSetWindowAttributes xswa;
+    XWindowAttributes xwa;
+
+#ifdef USE_PIXMAP
+    Pixmap winbuf;
+#else
+    XImage* winbuf;
+#endif
+
+    U8*currentscr;
+
+    int x,y;
+    int lenx,leny;
+    int bpp;
+    int bypp;
+    Window mywin;
+    XGCValues xgcv;
+    XSizeHints *xsh;
+    
+    pthread_mutex_t wmutex;
+
+    queue_t* queue;
+} QXWindow;
+
+static int lastbit(U32 bits)
+{
+    int t;
+    for(t=0;t<32;t++)
+    {
+	if(bits&1) break;
+	bits>>=1;
+    }
+    return t;
+}
+
+static int firstbit(U32 bits)
+{
+    int t,s=-1;
+    for(t=0;t<32;t++)
+    {
+	if(bits&1) s=t;
+	bits>>=1;
+    }
+    return s;
+}
+
+static U32 shiftl(U32 bits,int shift)
+{
+    if(shift>0) return bits<<shift;
+    else	return bits>>-shift;
+}
+
+static U32 getColorFromRGB(U8 r,U8 g,U8 b)
+{
+    U32 ret=0;
+    ret|=shiftl(r,(firstbit(X.v->red_mask)-7))&X.v->red_mask;
+    ret|=shiftl(g,(firstbit(X.v->green_mask)-7))&X.v->green_mask;
+    ret|=shiftl(b,(firstbit(X.v->blue_mask)-7))&X.v->blue_mask;
+    return ret;
+}
+
+static void whatever()
+{
+            XrmValue xrmvalue;
+            XrmDatabase rdb;
+            return;
+}
+
+static void*eventloop(void*);
+static int debug;
+static int initializexwindows()
+{
+    if(initialized)
+	return 1;
+    X.windowring=0;
+    X.d=0;
+    X.running=0;
+    pthread_mutex_init(&X.xmutex, 0);
+
+    //whatever();
+    /* open display, and show some information */
+    X.d=XOpenDisplay(0);//getenv("DISPLAY"));
+    if(!X.d) {return 0;}
+/*    printf("Xprotocol V%d.%d Vendor:%s Name:%s Defaults:%s",X.d->proto_major_version,
+     			       X.d->proto_minor_version,
+			       X.d->vendor,X.d->display_name,X.d->defaults);
+    int t;
+    printf("Formats:\n");
+    for(t=0;t<X.d->nformats;t++) {
+	ScreenFormat*sf=&X.d->pixmap_formats[t];
+	printf("%d:depth:%d, bpp:%d, scanline:%d\n",sf->depth,sf->bits_per_pixel,sf->scanline_pad);
+    }
+    printf("Screens:\n");
+    for(t=0;t<X.d->nscreens;t++) {
+	Screen*s=&X.d->screens[t];
+	printf("%d*%d, bpp:%d\n",s->width,s->height,s->root_depth);
+    }*/
+
+    /* open screen */
+    X.s=DefaultScreen(X.d);
+    if(debug) printf("Display:\n");
+    int xbig=DisplayWidth(X.d, X.s);
+    int ybig=DisplayHeight(X.d, X.s);
+    X.rootsizex=xbig;
+    X.rootsizey=ybig;
+    int bppbig=X.bpp=DisplayPlanes(X.d, X.s);
+    if(X.bpp==24) X.bypp=4; //Can this be 3, also?
+    if(X.bpp==16) X.bypp=2;
+    if(X.bpp==8) X.bypp=1;
+    if(debug) printf("%d*%d:%d/%d/%d\n",xbig,ybig,bppbig, X.bpp, X.bypp);
+    if(debug) printf("%d screens, vendor:%s, Ver:%d.%d(%d), at %s\n",
+    ScreenCount(X.d),
+    ServerVendor(X.d),
+    ProtocolVersion(X.d),
+    ProtocolRevision(X.d),
+    VendorRelease(X.d),
+    DisplayString(X.d));
+
+    /* open visual */
+    X.v=XDefaultVisualOfScreen(DefaultScreenOfDisplay(X.d));
+
+    X.isnative24 = (bppbig==24 && X.v->red_mask==0xff0000 &&
+	              X.v->green_mask==0x00ff00 &&
+		      X.v->blue_mask==0x0000ff);
+    X.isnative16 = (bppbig==16 && X.v->red_mask==0xf800 &&
+	              X.v->green_mask==0x07e0 &&
+		      X.v->blue_mask==0x1f);
+    X.isnative8 = (bppbig==8);
+    if(debug) printf("8bpp:%d 16bpp:%d 24(32)bpp:%d\n",X.isnative8,X.isnative16,X.isnative24);
+
+    X.root=DefaultRootWindow(X.d);
+    if(!X.root) {return 0;}
+
+    X.atom_wm = XInternAtom( X.d, "WM_PROTOCOLS", False );
+    X.atom_wmdelete = XInternAtom( X.d, "WM_DELETE_WINDOW", False );
+
+    X.cmap=DefaultColormap(X.d,X.s);
+    X.white=WhitePixel(X.d,X.s);
+    X.black=BlackPixel(X.d,X.s);
+
+    /* start event handler thread */
+    X.running = 1;
+    pthread_create(&X.eventhandler,0,eventloop,0);
+
+    X.stopall=0;
+    
+    initialized=1;
+    return 1;
+}
+
+//needed to set the border attribute
+#define MWM_HINTS_FUNCTIONS     (1L << 0)
+#define MWM_HINTS_DECORATIONS   (1L << 1)
+#define MWM_HINTS_INPUT_MODE    (1L << 2)
+#define MWM_HINTS_STATUS        (1L << 3)
+
+#define MWM_FUNC_ALL            (1L << 0)
+#define MWM_FUNC_RESIZE         (1L << 1)
+#define MWM_FUNC_MOVE           (1L << 2)
+#define MWM_FUNC_MINIMIZE       (1L << 3)
+#define MWM_FUNC_MAXIMIZE       (1L << 4)
+#define MWM_FUNC_CLOSE          (1L << 5)
+
+#define MWM_DECOR_ALL           (1L << 0)
+#define MWM_DECOR_BORDER        (1L << 1)
+#define MWM_DECOR_RESIZEH       (1L << 2)
+#define MWM_DECOR_TITLE         (1L << 3)
+#define MWM_DECOR_MENU          (1L << 4)
+#define MWM_DECOR_MINIMIZE      (1L << 5)
+#define MWM_DECOR_MAXIMIZE      (1L << 6)
+
+#define MWM_INPUT_MODELESS 0
+#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
+#define MWM_INPUT_SYSTEM_MODAL 2
+#define MWM_INPUT_FULL_APPLICATION_MODAL 3
+#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL
+
+typedef struct _mwmhints {
+  unsigned int flags;
+  unsigned int functions;
+  unsigned int decorations;
+  int input_mode;
+  unsigned int status;
+} MWMHints;
+
+static QXWindow* openwindow(int posx,int posy,int w,int h,char*winName)
+{
+    int noborder = 0;
+    XTextProperty iname;
+    XTextProperty wname;
+
+    pthread_mutex_lock(&X.xmutex);
+
+    if(!initialized) {
+	fprintf(stderr, "Error: XWindows not yet initialized!\n");
+	pthread_mutex_unlock(&X.xmutex);
+	return 0;
+    }
+
+    QXWindow*qx= malloc(sizeof(QXWindow));
+    if(!X.windowring) {
+	qx->next=qx;
+	qx->prev=qx;
+	X.windowring=qx;
+    } else {
+	qx->next=X.windowring;
+	qx->prev=X.windowring->prev;
+	qx->prev->next=qx;
+	X.windowring->prev=qx;
+	X.windowring=qx;
+    }
+
+    char*iconName=winName;
+    qx->x = posx;
+    qx->y = posy;
+    qx->lenx=w;
+    qx->leny=h;
+
+    qx->mywin=0;
+    qx->mywin=XCreateSimpleWindow(X.d,X.root,posx,posy,qx->lenx,qx->leny,0,X.white,X.black);
+
+    if(!qx->mywin) {
+	printf("Error: Couldn't create SimpleWindow\n");
+	pthread_mutex_unlock(&X.xmutex);
+	return 0;
+    }
+    qx->xwmh=XAllocWMHints();
+    qx->xsh=XAllocSizeHints();
+    qx->xch=XAllocClassHint();
+
+    qx->xsh->flags=(PPosition|PSize|PMinSize|PMaxSize);
+    qx->xsh->height=qx->xsh->min_height=qx->xsh->max_height=h;
+    qx->xsh->width =qx->xsh->min_width =qx->xsh->max_width =w;
+    qx->xsh->x=0;
+    qx->xsh->y=0;
+
+    if(!XStringListToTextProperty(&winName, 1, &wname)) {
+	printf("Error: XStringToTextProperty failed\n");
+	pthread_mutex_unlock(&X.xmutex);
+	return 0;
+    }
+    if(!XStringListToTextProperty(&iconName, 1, &iname)) {
+	printf("Error: XStringToTextProperty failed\n");
+	pthread_mutex_unlock(&X.xmutex);
+	return 0;
+    }
+
+    XSetWMProperties(X.d,qx->mywin,&wname,&iname,0,0,qx->xsh,qx->xwmh,qx->xch);
+
+    qx->xgcv.foreground=X.white;
+    qx->xgcv.background=X.black;
+    qx->gc=XCreateGC(X.d,qx->mywin,GCForeground|GCBackground,&qx->xgcv);
+
+    XGetWindowAttributes(X.d,qx->mywin,&qx->xwa);
+
+    // enable events for close window
+    XChangeProperty(X.d, qx->mywin, X.atom_wm, XA_ATOM, 32, PropModeReplace, (unsigned char *)(&X.atom_wmdelete), 1 );
+
+    // no border
+    // (This code comes from the project xine (xine.sourceforge.net)
+    //  I wonder if this works with all windowmanagers, though)
+    if(noborder>0)
+    {
+	Atom atomprop = XInternAtom(X.d, "_MOTIF_WM_HINTS", True);
+	if(atomprop)
+	{
+	    MWMHints mwmhints;
+	    mwmhints.flags = MWM_HINTS_DECORATIONS;
+	    if(noborder==1) mwmhints.decorations = 2;
+	    if(noborder>1) mwmhints.decorations = 0;
+	    XChangeProperty(X.d, qx->mywin, atomprop, atomprop, 32,
+			    PropModeReplace, (unsigned char *) &mwmhints, 5);
+	    XSetTransientForHint (X.d, qx->mywin, X.root);
+	}
+    }
+
+    qx->bpp=qx->xwa.depth;
+    if(qx->bpp==24) qx->bypp=4; //Can this be 3, also?
+    if(qx->bpp==16) qx->bypp=2;
+    if(qx->bpp==8) qx->bypp=1;
+
+#ifdef USE_SHM
+    XShmSegmentInfo segInfo;
+    int bpl = qx->lenx*qx->bypp;
+    segInfo.readOnly = 0;
+    segInfo.shmid = shmget(IPC_PRIVATE,qx->leny*bpl,IPC_CREAT|0777);
+    struct shmid_ds buf;
+    if (segInfo.shmid <0) {
+	perror("shmget");
+	fprintf(stderr,"Size = %d x %d\n", qx->lenx, qx->leny);
+    }
+    segInfo.shmaddr = (char*)shmat (segInfo.shmid, 0, 0);
+    if ((long)segInfo.shmaddr == -1) {
+	perror("shmat");
+    }
+    XShmAttach(X.d, &segInfo);
+    if (shmctl(segInfo.shmid, IPC_RMID, &buf) < 0) 
+	perror("shmctl");
+
+    qx->currentscr = (U8*)segInfo.shmaddr;
+
+# ifdef USE_PIXMAP
+    qx->winbuf = XShmCreatePixmap(X.d,qx->mywin,segInfo.shmaddr,&segInfo,qx->lenx,qx->leny,DefaultDepth(X.d, DefaultScreen(X.d)));
+# else 
+    qx->winbuf = XShmCreateImage(X.d,X.v,24,ZPixmap,(char*)segInfo.shmaddr, &segInfo, qx->lenx,qx->leny);
+    XInitImage(qx->winbuf);
+# endif
+
+#else
+
+# ifdef USE_PIXMAP
+    qx->winbuf = XCreatePixmap(X.d,qx->mywin,qx->lenx,qx->leny, DefaultDepth(X.d,X.s));
+# else
+    qx->currentscr=malloc(qx->lenx*qx->leny*4);
+    qx->winbuf = XCreateImage(X.d,X.v,24,ZPixmap,0,(char*)qx->currentscr,qx->lenx,qx->leny,8,qx->lenx*4);
+    XInitImage(qx->winbuf);
+# endif
+
+#endif
+    XSync(X.d, False);
+
+    /* get the image data for the area this window will be/is placed on */
+    /*{
+	Window tmpwin;
+	XImage*background;
+	int x,y;
+	XTranslateCoordinates(X.d,qx->mywin,X.root,0,0,&x,&y,&tmpwin);
+	qx->background = XGetImage(X.d, DefaultRootWindow(X.d), x, y, qx->lenx, qx->leny, AllPlanes, ZPixmap);
+	printf("%d %d\n",x,y);
+    }*/
+    
+    XMapRaised(X.d,qx->mywin);
+    XFlush(X.d);
+
+    qx->xswa.event_mask=(qx->xwa.your_event_mask|=
+	    ButtonPressMask|
+	    ButtonReleaseMask|
+	    //ExposureMask|
+	    KeyPressMask|
+    	    MotionNotify|
+    	    EnterWindowMask|
+    	    LeaveWindowMask|
+    	    PointerMotionMask
+	);
+    XChangeWindowAttributes(X.d,qx->mywin,CWEventMask,&qx->xswa);
+
+    qx->queue = queue_init(sizeof(gfxevent_t), 256);
+    
+    pthread_mutex_unlock(&X.xmutex);
+	
+    pthread_mutex_init(&qx->wmutex, 0);
+    return qx;
+}
+
+static void closeWindow(QXWindow*qx)
+{
+    if(qx->mywin) {
+	pthread_mutex_lock(&X.xmutex);
+	XDestroyWindow(X.d,qx->mywin);
+	pthread_mutex_unlock(&X.xmutex);
+	qx->mywin = 0;
+    }
+}
+
+static void processEvent(gfxevent_t*event)
+{
+    fd_set fdset;
+    struct timeval de;
+    int status;
+
+    XEvent xe;
+
+    FD_ZERO(&fdset);
+    FD_SET(ConnectionNumber(X.d),&fdset);
+    de.tv_sec = 0;
+    de.tv_usec = 5000; // 1/200 s
+
+    pthread_mutex_lock(&X.xmutex);
+    FD_ZERO(&fdset);
+    FD_SET(ConnectionNumber(X.d),&fdset);
+    de.tv_sec = de.tv_usec = 0;
+    if(!select(ConnectionNumber(X.d)+1, &fdset, 0, 0, &de)) {
+	pthread_mutex_unlock(&X.xmutex);
+	usleep(1000);
+	return;
+    }
+    XNextEvent(X.d,&xe);
+    pthread_mutex_unlock(&X.xmutex);
+    
+    /* 1: find out which windows the message is for */
+    Window w = 0;
+    switch(xe.type)
+    {
+	case ClientMessage: w = xe.xclient.window;break;
+	case Expose:	    w = xe.xexpose.window;break;
+	case NoExpose:	    w = xe.xexpose.window;break;
+	case ButtonPress:   w = xe.xbutton.window;break;
+	case ButtonRelease: w = xe.xbutton.window;break;
+	case KeyPress:	    w = xe.xkey.window;   break;
+	case KeyRelease:    w = xe.xkey.window;   break;
+	case MotionNotify:  w = xe.xmotion.window;break;
+	case EnterNotify:   w = xe.xmotion.window;break;
+	case LeaveNotify:   w = xe.xmotion.window;break;
+	default:
+	/* this usually happens for unknown events which
+	   we don't care about */
+	    return;
+    }
+
+    QXWindow*qx=X.windowring;
+    QXWindow*win=0;
+    event->internal = 0;
+    do {
+	if(w == qx->mywin) {
+	    win = qx;
+	}
+    }
+    while(qx!=X.windowring);
+    
+    if(!win) {
+	/* Not one of our windows. This may be a bug */
+	return;
+    }
+    event->internal = win;
+
+    /* 2: Go for the event construction */
+
+    switch(xe.type)
+    {
+	case ButtonPress:
+	    event->type = GFXEVENT_MOUSEPRESS;
+	    event->button = xe.xbutton.button;
+	break;
+	case ButtonRelease:
+	    event->type = GFXEVENT_MOUSERELEASE;
+	    event->button = xe.xbutton.button;
+	break;
+	case KeyPress:
+	    event->type = GFXEVENT_KEYPRESS;
+	    event->key = xe.xkey.keycode;
+	break;
+	case KeyRelease:
+	    event->type = GFXEVENT_KEYRELEASE;
+	    event->key = xe.xkey.keycode;
+	break;
+	case MotionNotify:
+	    event->type = GFXEVENT_MOUSEMOVE;
+	    pthread_mutex_lock(&qx->wmutex);
+	    event->x = xe.xmotion.x_root - win->x;
+	    event->y = xe.xmotion.y_root - win->y;
+	    if(!queue_put(win->queue, event)) {
+		printf("Queue overflow for window %08x!\n", win);
+	    }
+	    pthread_mutex_unlock(&qx->wmutex);
+	break;
+	case EnterNotify:
+	    event->type = GFXEVENT_MOUSEENTER;
+	    pthread_mutex_lock(&qx->wmutex);
+	    event->x = xe.xmotion.x_root - win->x;
+	    event->y = xe.xmotion.y_root - win->y;
+	    pthread_mutex_unlock(&qx->wmutex);
+	break;
+	case LeaveNotify:
+	    event->type = GFXEVENT_MOUSELEAVE;
+	    pthread_mutex_lock(&qx->wmutex);
+	    event->x = xe.xmotion.x - win->x;
+	    event->y = xe.xmotion.y - win->y;
+	    pthread_mutex_unlock(&qx->wmutex);
+	break;
+	case ClientMessage:
+	    if ((xe.xclient.message_type == X.atom_wm ) &&
+		((unsigned)xe.xclient.data.l[0] == X.atom_wmdelete) ) {
+	        pthread_mutex_lock(&qx->wmutex);
+		closeWindow(win);
+		event->type = GFXEVENT_DESTROY;
+	        pthread_mutex_unlock(&qx->wmutex);
+	    }
+	break;
+    }
+}
+
+static void*eventloop(void*r)
+{
+    //while(!XEventsQueued(X.d,QueuedAfterReading))
+    while(X.running)
+    {
+	gfxevent_t event;
+	event.type = GFXEVENT_NOTHING;
+	event.key = event.x = event.y = event.button = -1;
+	processEvent(&event);
+	if(event.type != GFXEVENT_NOTHING && event.type != GFXEVENT_MOUSEMOVE) {
+	    QXWindow*win = (QXWindow*)event.internal;
+	    pthread_mutex_lock(&win->wmutex);
+	    if(!queue_put(win->queue,&event)) {
+		fprintf(stderr, "Queue overflow for window %08x!\n", win);
+	    }
+	    pthread_mutex_unlock(&win->wmutex);
+	}
+    }
+    return 0;
+}
+
+typedef struct _internal {
+    GC gc;
+    char*name;
+    QXWindow*qx;
+    int lenx, leny;
+    int tmplenx, tmpleny;
+    void*currentscr2;
+} internal_t;
+
+static void gfxwindow_on(gfxwindow_t*win)
+{
+    internal_t*i = (internal_t*)win->internal;
+	 
+    i->qx=openwindow(64, 64, win->width, win->height, i->name);
+    if(!i->qx)
+	return;
+    i->currentscr2=0;
+    if(i->qx->bypp != 4) {
+	fprintf(stderr, "Warning: Not a native 32 bit screen, using second buffer\n");
+	i->currentscr2 = malloc(win->width*win->height*4);
+	win->currentscr = (unsigned char*)i->currentscr2;
+    } else {
+	win->currentscr = i->qx->currentscr;
+    }
+    win->lastscr = 0;
+}
+
+static void gfxwindow_off(gfxwindow_t*win)
+{
+    internal_t*i = (internal_t*)win->internal;
+    if(i->currentscr2)
+	free(i->currentscr2);
+    closeWindow(i->qx);
+}
+
+static void gfxwindow_flippage(gfxwindow_t*win)
+{
+    internal_t*i = (internal_t*)win->internal;
+    pthread_mutex_lock(&X.xmutex);
+
+    if(i->currentscr2) {
+	if(i->qx->bypp==2 && X.isnative16) {
+	    int t;
+	    int l = win->width*win->height;
+	    unsigned char*dest = i->qx->currentscr;
+	    unsigned char*src = (unsigned char*)i->currentscr2;
+	    do {
+		dest[1] = (src[2]&0xf8)|(src[1]>>5);
+		dest[0] = ((src[1]<<5)&0xe0)|(src[0]>>3);
+		dest+=2;
+		src+=4;
+	    } while(--l);
+	} else {
+	    memcpy(i->qx->currentscr, i->currentscr2, i->lenx*i->leny*i->qx->bypp);
+	}
+    }
+
+#ifdef USE_PIXMAP
+    XSetFunction(X.d,i->qx->gc,GXcopy);
+    XCopyArea(X.d,i->qx->winbuf,i->qx->mywin,i->qx->gc, 0, 0, i->qx->lenx,i->qx->leny, 0, 0);
+    XFlush(X.d);
+#else
+    XPutImage(X.d,qx->mywin,qx->gc,qx->winbuf,0,0,0,0,lenx,leny);
+#endif
+    pthread_mutex_unlock(&X.xmutex);
+}
+
+void gfxwindow_setcolor(gfxwindow_t*win, U32 c)
+{
+    internal_t*i = (internal_t*)win->internal;
+    pthread_mutex_lock(&X.xmutex);
+    i->qx->xgcv.foreground=getColorFromRGB((U8)(c>>16),(U8)(c>>8),(U8)c);
+    i->gc=XCreateGC(X.d,i->qx->mywin,GCForeground|GCBackground,&i->qx->xgcv);
+    pthread_mutex_unlock(&X.xmutex);
+}
+void gfxwindow_putpixel(gfxwindow_t*win, int x, int y, unsigned char c)
+{
+    internal_t*i = (internal_t*)win->internal;
+    if(((U32)x)<(U32)win->width && ((U32)y)<(U32)win->height)
+	*(U32*)&win->currentscr[y*win->width*i->qx->bypp+x*i->qx->bypp]=c;
+}
+static gfxevent_t gfxwindow_getEvent(gfxwindow_t*win)
+{
+    internal_t*i = (internal_t*)win->internal;
+    gfxevent_t event;
+    pthread_mutex_lock(&i->qx->wmutex);
+    if(!i->qx->queue || !queue_get(i->qx->queue,&event)) {
+	event.type = GFXEVENT_NOTHING;
+    } else if(event.type == GFXEVENT_DESTROY) {
+	queue_destroy(i->qx->queue);i->qx->queue=0;
+    }
+    pthread_mutex_unlock(&i->qx->wmutex);
+    return event;
+}
+   
+static void gfxwindow_move(gfxwindow_t*win, int x,int y)
+{
+    internal_t*i = (internal_t*)win->internal;
+    pthread_mutex_lock(&i->qx->wmutex);
+    pthread_mutex_lock(&X.xmutex);
+    XWindowAttributes a;
+    i->qx->x += x;
+    i->qx->y += y;
+    XMoveResizeWindow(X.d, i->qx->mywin, i->qx->x, i->qx->y, i->tmplenx, i->tmpleny);
+
+    queue_t* queue2 = queue_init(sizeof(gfxevent_t), 256);
+    gfxevent_t event;
+    /* HACK: now that we have moved the window, all mouse move events
+       are outdated- remove them*/
+    while(queue_get(i->qx->queue, &event)) {
+	if(event.type!=GFXEVENT_MOUSEMOVE)
+	    queue_put(queue2, &event);
+    }
+    queue_destroy(i->qx->queue);
+    i->qx->queue = queue2;
+
+    pthread_mutex_unlock(&X.xmutex);
+    pthread_mutex_unlock(&i->qx->wmutex);
+}
+
+static void gfxwindow_resize(gfxwindow_t*win, int x,int y)
+{
+    internal_t*i = (internal_t*)win->internal;
+    if(x>win->width || y>win->height) {
+	fprintf(stderr, "resize: can only make windows smaller\n");
+	return;
+    }
+    if(x<1) x=1;
+    if(y<1) y=1;
+    pthread_mutex_lock(&i->qx->wmutex);
+    i->tmplenx=x;
+    i->tmpleny=y;
+    pthread_mutex_lock(&X.xmutex);
+    XMoveResizeWindow(X.d, i->qx->mywin, i->qx->x, i->qx->y, i->tmplenx, i->tmpleny);
+    pthread_mutex_unlock(&X.xmutex);
+    pthread_mutex_unlock(&i->qx->wmutex);
+}
+static void gfxwindow_destroy(gfxwindow_t*win)
+{
+    internal_t*i = (internal_t*)win->internal;
+    gfxwindow_off(win);
+    pthread_mutex_destroy(&i->qx->wmutex);
+}
+
+gfxwindow_t* gfxwindow_new(int width, int height)
+{
+    gfxwindow_t*w = (gfxwindow_t*)malloc(sizeof(gfxwindow_t));
+    if(!initializexwindows()) {
+	fprintf(stderr, "Warning: Couldn't initialize X-Windows\n");
+    }
+    internal_t*i = malloc(sizeof(internal_t));
+    w->internal = i;
+    w->move = gfxwindow_move;
+    w->resize = gfxwindow_resize;
+    w->flippage = gfxwindow_flippage;
+    w->getEvent = gfxwindow_getEvent;
+    w->width = width;
+    w->height = height;
+    w->destroy = gfxwindow_destroy;
+
+    i->lenx = i->tmplenx = width;
+    i->leny = i->tmpleny = height;
+    i->name = "";
+
+    gfxwindow_on(w);
+    return w;
+};
+
diff --git a/lib/gfxwindow_win32.c b/lib/gfxwindow_win32.c
new file mode 100644
index 0000000..ae661b0
--- /dev/null
+++ b/lib/gfxwindow_win32.c
@@ -0,0 +1,430 @@
+/* gfxwindow.h 
+
+   Simple GUI abstraction- Windows implementation
+
+   Part of the swftools package.
+
+   Copyright (c) 2005 Matthias Kramm <kramm@quiss.org> 
+
+   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 <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+#include <string.h>
+#include "gfx.h"
+
+static LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+static char szWinName[] = "MyWin";
+static HDC hdc;
+static HWND hwnd;
+static char*text="";
+static int textx;
+static int texty;
+static int a = 0;
+static HDC dc, memDc;
+static HBITMAP   piccy;
+
+static int sizex=640;
+static int sizey=388;
+static char *screen;
+static char *offscreen;
+static int screensize;
+
+static DWORD threadID;
+static DWORD mainthreadID;
+static HANDLE thread;
+static HINSTANCE me,prev;
+static int nWinMode;
+static int posx,posy;
+static RECT desktopSize;
+static int initialized = 0;
+
+static int cwidth=640,cheight=388;
+
+#define DIB
+
+static void openWindow(int _sizex, int _sizey)
+{
+    RECT r;int ok;
+
+    sizex = _sizex;
+    sizey = _sizey;
+    
+    ok = (int)GetClientRect(GetDesktopWindow(), &r);
+    if(!ok) {
+	r.left = r.top = 0;
+	r.right = 1280;
+	r.bottom = 1024;
+    }
+    desktopSize = r;
+
+    hwnd=CreateWindow(szWinName,
+		      0, //window title
+		      WS_POPUP|WS_VISIBLE,
+		      posx=100, //CW_USEDEFAULT,
+		      posy=200, //CW_USEDEFAULT,
+		      640,388,
+		      HWND_DESKTOP,
+		      NULL,me,NULL);
+    SendMessage(hwnd, 1024+5 /*SB_SETBORDERS*/, 0, 0);
+    
+    ShowWindow(hwnd,nWinMode);
+    UpdateWindow(hwnd);
+
+    dc=GetDC(hwnd);
+    memDc=CreateCompatibleDC(dc);
+//    SetTimer(hwnd,1,1000,NULL);
+//    SetTimer(hwnd,1,33,NULL);
+
+#ifdef DIB
+    void * ppvBits = 0;
+    BITMAPINFO info;
+    memset(&info, sizeof(info), 0);
+    info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    info.bmiHeader.biWidth = sizex;
+    info.bmiHeader.biHeight = sizey;
+    info.bmiHeader.biPlanes= 1;
+    info.bmiHeader.biBitCount = 24;
+    info.bmiHeader.biCompression = BI_RGB;
+    info.bmiHeader.biSizeImage = sizex*sizey*3;
+
+    piccy = CreateDIBSection(0, &info, DIB_RGB_COLORS, &ppvBits, 0,0);
+    screen = (char*)ppvBits;
+    offscreen = (char*)malloc(sizex*sizey*4);
+    screensize = sizex*sizey*3;
+    GdiFlush();
+#else
+    screen = (char*)malloc(sizex*sizey*3);
+    offscreen = (char*)malloc(sizex*sizey*4);
+    screensize = sizex*sizey*3;
+    piccy = CreateBitmap(sizex, sizey, 1, 24, screen);
+#endif
+
+    SelectObject(memDc,piccy);
+    
+}
+
+static void closeWindow()
+{
+    DeleteDC(memDc);
+    ReleaseDC(hwnd,dc);
+    KillTimer(hwnd,1);
+}
+
+static int initwin32()
+{
+    MSG msg;
+    int ret;
+    WNDCLASS wcl;
+
+    me =  GetModuleHandle(NULL);
+    prev = NULL;
+    nWinMode = SW_SHOW;
+
+    if(GetClassInfo(0, szWinName, &wcl)) {
+	/* already registered */
+	exit(1);
+    }
+    wcl.hInstance    =me;
+    wcl.lpszClassName=szWinName;
+    wcl.lpfnWndProc  =WindowFunc;
+    wcl.style        =2;
+    wcl.hIcon        =LoadIcon  (NULL, IDI_HAND);
+    wcl.hCursor      =LoadCursor(NULL, IDC_HAND);//IDC_CROSS);
+    wcl.lpszMenuName =NULL;
+    wcl.cbClsExtra   =0;
+    wcl.cbWndExtra   =0;
+    wcl.hbrBackground=(HBRUSH)GetStockObject(NULL_BRUSH);//WHITE_BRUSH);
+
+    if(!RegisterClass(&wcl)) 
+	exit(1);
+
+    //mainthreadID = GetCurrentThreadId();
+
+    //openWindow(640,388);
+
+    //thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(maincaller), (/*data*/0), 0, (LPDWORD)&(threadID));
+  
+    /*while(GetMessage(&msg,NULL,0,0))
+    {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+    }*/
+
+    //closeWindow();
+    //ret = msg.wParam;
+
+    initialized = 1;
+
+    return ret;
+}
+
+#define Q_REDRAW 0x7f01
+#define Q_DUMMY  0x7f02
+
+static LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+   case WM_DESTROY:
+    PostQuitMessage(0);
+    break;
+   case WM_PAINT:
+    BitBlt(dc,0,0,sizex,sizey,memDc,0,0,SRCCOPY);
+   break;
+   case Q_DUMMY:
+   break;
+   case Q_REDRAW: {
+    int x,y;
+    for(y=0;y<sizey;y++) {
+	unsigned char*o = (unsigned char*)&offscreen[y*sizex*4];
+	unsigned char*s = (unsigned char*)&screen[(sizey-y-1)*sizex*3];
+	for(x=0;x<sizex;x++) {
+	    s[0] = o[0];
+	    s[1] = o[1];
+	    s[2] = o[2];
+	    s+=3;
+	    o+=4;
+	}
+    }
+
+#ifndef DIB
+    SetBitmapBits(piccy, screensize, screen);
+    InvalidateRect(hwnd,NULL,1);
+#endif
+
+#ifdef DIB
+    //SetDIBitsToDevice
+    BitBlt(dc,0,0,sizex,sizey,memDc,0,0,SRCCOPY);
+#else
+    BitBlt(dc,0,0,sizex,sizey,memDc,0,0,SRCCOPY);
+#endif
+   break;
+   }
+   case WM_TIMER:
+    //InvalidateRect(hwnd,NULL,1);
+   default:
+    return DefWindowProc(hwnd, message, wParam, lParam);
+ }
+ return 0;
+}
+
+static void ModeRGB_on(window_t*win)
+{
+    MSG msg;
+    //printf("on()\n");
+    openWindow(sizex, sizey);
+    win->currentscr = (unsigned char*)offscreen;
+
+    while(GetMessage(&msg,NULL,0,0))
+    {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+	if(msg.message == WM_PAINT)
+	    break;
+    }
+}
+static void ModeRGB_off(window_t*win)
+{
+    MSG msg;
+    //printf("off()\n");
+    //TODO: shouldn't this be DestroyWindow(hwnd)?
+    PostMessage(hwnd, WM_DESTROY, 0, 0);
+    while(GetMessage(&msg,NULL,0,0))
+    {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+	if(msg.message == WM_DESTROY)
+	    break;
+    }
+    closeWindow();
+    win->currentscr = win->lastscr = 0;
+}
+static void ModeRGB_flippage(window_t*win)
+{
+    MSG msg;
+    PostMessage(hwnd, Q_REDRAW, 0, 0);
+    while(GetMessage(&msg,NULL,0,0))
+    {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+	if(msg.message == Q_REDRAW)
+	    break;
+    }
+    win->currentscr = (byte*)offscreen;
+}
+static gfxevent_t ModeRGB_getEvent(window_t*win)
+{
+    MSG msg;
+    WPARAM wParam;
+    LPARAM lParam;
+    gfxevent_t event;
+
+    //PostMessage(hwnd, Q_DUMMY, 0, 0);
+
+    event.type = GFXEVENT_NOTHING;
+    event.key = 0;
+    event.x = 0;
+    event.y = 0;
+    event.type = 0;
+    event.button = 0;
+
+    if(!PeekMessage(&msg,NULL,0,0,0))
+	return event;//nothing
+
+    while(GetMessage(&msg,NULL,0,0))
+    {
+	lParam = msg.lParam;
+	wParam = msg.wParam;
+	if(msg.message == Q_DUMMY) {
+	    event.type = GFXEVENT_NOTHING;
+	    break;
+	} else if(msg.message == WM_LBUTTONDOWN) {
+	    event.type = GFXEVENT_MOUSEPRESS;
+	    event.button = 1;
+	    event.x = (signed short int)LOWORD(lParam);
+	    event.y = (signed short int)HIWORD(lParam);
+	    SetCapture(hwnd);
+	    break;
+	} else if(msg.message == WM_LBUTTONUP) {
+	    event.type = GFXEVENT_MOUSERELEASE;
+	    event.button = 1;
+	    event.x = (signed short int)LOWORD(lParam);
+	    event.y = (signed short int)HIWORD(lParam);
+	    ReleaseCapture();
+	    break;
+	} else if(msg.message == WM_MBUTTONDOWN) {
+	    event.type = GFXEVENT_MOUSEPRESS;
+	    event.button = 2;
+	    event.x = (signed short int)LOWORD(lParam);
+	    event.y = (signed short int)HIWORD(lParam);
+	    SetCapture(hwnd);
+	    break;
+	} else if(msg.message == WM_MBUTTONUP) {
+	    event.type = GFXEVENT_MOUSERELEASE;
+	    event.button = 1;
+	    event.x = (signed short int)LOWORD(lParam);
+	    event.y = (signed short int)HIWORD(lParam);
+	    ReleaseCapture();
+	    break;
+	} else if(msg.message == WM_RBUTTONDOWN) {
+	    event.type = GFXEVENT_MOUSEPRESS;
+	    event.button = 3;
+	    event.x = (signed short int)LOWORD(lParam);
+	    event.y = (signed short int)HIWORD(lParam);
+	    SetCapture(hwnd);
+	    break;
+	} else if(msg.message == WM_RBUTTONUP) {
+	    event.type = GFXEVENT_MOUSERELEASE;
+	    event.button = 3;
+	    event.x = (signed short int)LOWORD(lParam);
+	    event.y = (signed short int)HIWORD(lParam);
+	    ReleaseCapture();
+	    break;
+	} else if(msg.message == WM_MOUSEMOVE) {
+	    event.type = GFXEVENT_MOUSEMOVE;
+	    event.x = (signed short int)LOWORD(lParam);
+	    event.y = (signed short int)HIWORD(lParam);
+	    break;
+	} else if(msg.message == WM_CHAR) {
+	    event.type = GFXEVENT_KEYPRESS;
+	    event.key = (char)wParam;
+	    break;
+	} else {
+	    TranslateMessage(&msg);
+	    DispatchMessage(&msg);
+	    event.type = GFXEVENT_NOTHING;
+	    break;
+	}
+    }
+    return event;
+}
+static void ModeRGB_move(window_t*win, int relx,int rely)
+{
+    MSG msg;
+    PostMessage(hwnd, Q_DUMMY, 0, 0);
+    while(GetMessage(&msg,NULL,0,0))
+    {
+	if(msg.message == WM_LBUTTONUP) {
+	    SendMessage(hwnd, msg.message, msg.wParam, msg.lParam);
+	    return;
+	}
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+	if(msg.message == Q_DUMMY)
+	    break;
+    }
+    posx+=relx;
+    posy+=rely;
+   
+    if(posx > desktopSize.right-cwidth) posx = desktopSize.right-cwidth;
+    if(posy > desktopSize.bottom-cheight) posy = desktopSize.bottom-cheight;
+    if(posx < desktopSize.left) posx = desktopSize.left;
+    if(posy < desktopSize.top) posy = desktopSize.top;
+
+    SetWindowPos(hwnd, HWND_TOP, posx, posy, 0, 0, SWP_NOSIZE);
+    PostMessage(hwnd, Q_DUMMY, 0, 0);
+    while(GetMessage(&msg,NULL,0,0))
+    {
+	if(msg.message == WM_LBUTTONUP) {
+	    SendMessage(hwnd, msg.message, msg.wParam, msg.lParam);
+	    break;;
+	}
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+	if(msg.message == Q_DUMMY)
+	    break;
+    }
+}
+static void ModeRGB_resize(window_t*win, int width,int height)
+{
+    if(width>sizex || height>sizey) {
+	printf("mode24::resize: can only make windows smaller\n");
+	return;
+    }
+    if(width<1) width=1;
+    if(height<1) height=1;
+    cwidth = width;
+    cheight = height;
+    SetWindowPos(hwnd, HWND_TOP, 0, 0, width, height, SWP_NOMOVE);
+    win->move(win,0,0);
+}
+
+
+window_t* window_new(window_t*win, int width, int height)
+{
+    window_t*w = (window_t*)malloc(sizeof(window_t));
+    memset(w, 0, sizeof(window_t));
+    if(!initialized)
+	initwin32();
+    w->currentscr = w->lastscr = 0;
+    sizex = width;
+    sizey = height;
+    cwidth = sizex;
+    cheight = sizey;
+    //printf("contruct(%d, %d)\n", x, y);
+    w->on = ModeRGB_on;
+    w->off = ModeRGB_off;
+    w->move = ModeRGB_move;
+    w->resize = ModeRGB_resize;
+    w->flippage = ModeRGB_flippage;
+    w->getEvent = ModeRGB_getEvent;
+    w->width = width;
+    w->height = height;
+    return w;
+}
+
-- 
1.7.10.4