fix crashes reported by Debian Cylab Mayhem Team
[swftools.git] / lib / gfxwindow_unix.c
blob28a8e7eafbc88e65c085e1a9e7c375b200e305c3
1 /* gfxwindow.h
3 Simple GUI abstraction- Unix implementation
5 Part of the swftools package.
7 Copyright (c) 2005 Matthias Kramm <kramm@quiss.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <pthread.h>
26 #include <memory.h>
27 #include <unistd.h>
28 #include <sys/ipc.h>
29 #include <sys/shm.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include <X11/Xresource.h>
33 #include <X11/xpm.h>
34 #include <X11/Xthreads.h>
35 #include <X11/Xatom.h>
36 #include <X11/extensions/XShm.h>
37 #include "gfxwindow.h"
38 #include "types.h"
40 #define USE_SHM 1
41 #define USE_PIXMAP 1 // use pixmap instead of ximage for off-screen rendering
43 #define initMutex(mutex) {pthread_mutex_init(mutex, 0);}
44 #define destroyMutex(mutex) {pthread_mutex_destroy((mutex));}
45 #define lockMutex(mutex) pthread_mutex_lock(mutex)
46 #define unlockMutex(mutex) pthread_mutex_unlock(mutex)
48 typedef struct _queue
50 char* data;
51 int readpos;
52 int writepos;
53 int number;
54 int size;
55 int nmemb;
56 pthread_mutex_t mutex;
57 } queue_t;
60 queue_t* queue_init(int size, int nmemb)
62 queue_t* queue = malloc(sizeof(queue_t));
63 queue->data = (char*)malloc(size * nmemb);
64 queue->size = size;
65 queue->nmemb = nmemb;
66 queue->readpos = 0;
67 queue->writepos = 0;
68 queue->number = 0;
69 initMutex(&queue->mutex);
70 return queue;
73 void queue_destroy(queue_t*queue)
75 free(queue->data);queue->data = 0;
76 destroyMutex(&queue->mutex);
77 memset(queue, 0, sizeof(queue_t));
80 int queue_put(queue_t*queue, void*data)
82 int tmp = queue->writepos+1;
83 tmp%=queue->nmemb;
85 lockMutex(&queue->mutex);
86 if(tmp==queue->readpos) {
87 unlockMutex(&queue->mutex);
88 return 0;
90 memcpy(&queue->data[queue->writepos*queue->size], data, queue->size);
91 queue->writepos = tmp;
92 queue->number++;
93 unlockMutex(&queue->mutex);
94 return 1;
97 int queue_get(queue_t*queue, void*data)
99 lockMutex(&queue->mutex);
100 if(queue->writepos == queue->readpos) {
101 unlockMutex(&queue->mutex);
102 return 0;
104 memcpy(data, &queue->data[queue->readpos*queue->size], queue->size);
105 queue->readpos++;
106 queue->readpos %= queue->nmemb;
107 queue->number--;
108 unlockMutex(&queue->mutex);
109 return 1;
112 void queue_flush(queue_t*queue)
114 lockMutex(&queue->mutex);
115 queue->number = 0;
116 queue->readpos = 0;
117 queue->writepos = 0;
118 unlockMutex(&queue->mutex);
121 int queue_num(queue_t*queue)
123 return queue->number;
126 static int initializexwindows();
128 struct _QXWindow;
129 struct X
131 char isnative24;
132 char isnative16;
133 char isnative8;
134 int bpp;
135 int bypp;
136 Atom atom_wm;
137 Atom atom_wmdelete;
139 int rootsizex;
140 int rootsizey;
142 Display *d;
143 Window root;
144 int s;
145 Visual*v;
147 char running;
148 pthread_t eventhandler;
149 pthread_mutex_t xmutex;
151 struct _QXWindow*windowring;
153 int stopall;
154 Colormap cmap;
155 U32 white;
156 U32 black;
158 static struct X X;
160 static int initialized = 0;
162 void destroyX() {
163 X.stopall=1;
164 if(X.running)
165 pthread_cancel(X.eventhandler);
166 if(X.d)
167 XCloseDisplay(X.d);
168 pthread_mutex_destroy(&X.xmutex);
171 typedef struct _QXWindow {
172 struct _QXWindow*next;
173 struct _QXWindow*prev;
175 XWMHints *xwmh;
176 XClassHint *xch;
178 GC gc;
179 //XFontStruct *xfs;
181 XSetWindowAttributes xswa;
182 XWindowAttributes xwa;
184 #ifdef USE_PIXMAP
185 Pixmap offscreen_pixmap;
186 #else
187 XImage* offscreen_ximage;
188 #endif
190 U8*currentscr;
192 int x,y;
193 int lenx,leny;
194 int bpp;
195 int bypp;
196 Window mywin;
197 XGCValues xgcv;
198 XSizeHints *xsh;
200 pthread_mutex_t wmutex;
202 queue_t* queue;
203 } QXWindow;
205 static int lastbit(U32 bits)
207 int t;
208 for(t=0;t<32;t++)
210 if(bits&1) break;
211 bits>>=1;
213 return t;
216 static int firstbit(U32 bits)
218 int t,s=-1;
219 for(t=0;t<32;t++)
221 if(bits&1) s=t;
222 bits>>=1;
224 return s;
227 static U32 shiftl(U32 bits,int shift)
229 if(shift>0) return bits<<shift;
230 else return bits>>-shift;
233 static U32 getColorFromRGB(U8 r,U8 g,U8 b)
235 U32 ret=0;
236 ret|=shiftl(r,(firstbit(X.v->red_mask)-7))&X.v->red_mask;
237 ret|=shiftl(g,(firstbit(X.v->green_mask)-7))&X.v->green_mask;
238 ret|=shiftl(b,(firstbit(X.v->blue_mask)-7))&X.v->blue_mask;
239 return ret;
242 static void whatever()
244 XrmValue xrmvalue;
245 XrmDatabase rdb;
246 return;
249 static void*eventloop(void*);
250 static int debug;
251 static int initializexwindows()
253 if(initialized)
254 return 1;
255 X.windowring=0;
256 X.d=0;
257 X.running=0;
258 pthread_mutex_init(&X.xmutex, 0);
260 //whatever();
261 /* open display, and show some information */
262 X.d=XOpenDisplay(0);//getenv("DISPLAY"));
263 if(!X.d) {return 0;}
264 /* printf("Xprotocol V%d.%d Vendor:%s Name:%s Defaults:%s",X.d->proto_major_version,
265 X.d->proto_minor_version,
266 X.d->vendor,X.d->display_name,X.d->defaults);
267 int t;
268 printf("Formats:\n");
269 for(t=0;t<X.d->nformats;t++) {
270 ScreenFormat*sf=&X.d->pixmap_formats[t];
271 printf("%d:depth:%d, bpp:%d, scanline:%d\n",sf->depth,sf->bits_per_pixel,sf->scanline_pad);
273 printf("Screens:\n");
274 for(t=0;t<X.d->nscreens;t++) {
275 Screen*s=&X.d->screens[t];
276 printf("%d*%d, bpp:%d\n",s->width,s->height,s->root_depth);
279 /* open screen */
280 X.s=DefaultScreen(X.d);
281 if(debug) printf("Display:\n");
282 int xbig=DisplayWidth(X.d, X.s);
283 int ybig=DisplayHeight(X.d, X.s);
284 X.rootsizex=xbig;
285 X.rootsizey=ybig;
286 int bppbig=X.bpp=DisplayPlanes(X.d, X.s);
287 if(X.bpp==24) X.bypp=4; //Can this be 3, also?
288 if(X.bpp==16) X.bypp=2;
289 if(X.bpp==8) X.bypp=1;
290 if(debug) printf("%d*%d:%d/%d/%d\n",xbig,ybig,bppbig, X.bpp, X.bypp);
291 if(debug) printf("%d screens, vendor:%s, Ver:%d.%d(%d), at %s\n",
292 ScreenCount(X.d),
293 ServerVendor(X.d),
294 ProtocolVersion(X.d),
295 ProtocolRevision(X.d),
296 VendorRelease(X.d),
297 DisplayString(X.d));
299 /* open visual */
300 X.v=XDefaultVisualOfScreen(DefaultScreenOfDisplay(X.d));
302 X.isnative24 = (bppbig==24 && X.v->red_mask==0xff0000 &&
303 X.v->green_mask==0x00ff00 &&
304 X.v->blue_mask==0x0000ff);
305 X.isnative16 = (bppbig==16 && X.v->red_mask==0xf800 &&
306 X.v->green_mask==0x07e0 &&
307 X.v->blue_mask==0x1f);
308 X.isnative8 = (bppbig==8);
309 if(debug) printf("8bpp:%d 16bpp:%d 24(32)bpp:%d\n",X.isnative8,X.isnative16,X.isnative24);
311 X.root=DefaultRootWindow(X.d);
312 if(!X.root) {return 0;}
314 X.atom_wm = XInternAtom( X.d, "WM_PROTOCOLS", False );
315 X.atom_wmdelete = XInternAtom( X.d, "WM_DELETE_WINDOW", False );
317 X.cmap=DefaultColormap(X.d,X.s);
318 X.white=WhitePixel(X.d,X.s);
319 X.black=BlackPixel(X.d,X.s);
321 /* start event handler thread */
322 X.running = 1;
323 pthread_create(&X.eventhandler,0,eventloop,0);
325 X.stopall=0;
327 initialized=1;
328 return 1;
331 //needed to set the border attribute
332 #define MWM_HINTS_FUNCTIONS (1L << 0)
333 #define MWM_HINTS_DECORATIONS (1L << 1)
334 #define MWM_HINTS_INPUT_MODE (1L << 2)
335 #define MWM_HINTS_STATUS (1L << 3)
337 #define MWM_FUNC_ALL (1L << 0)
338 #define MWM_FUNC_RESIZE (1L << 1)
339 #define MWM_FUNC_MOVE (1L << 2)
340 #define MWM_FUNC_MINIMIZE (1L << 3)
341 #define MWM_FUNC_MAXIMIZE (1L << 4)
342 #define MWM_FUNC_CLOSE (1L << 5)
344 #define MWM_DECOR_ALL (1L << 0)
345 #define MWM_DECOR_BORDER (1L << 1)
346 #define MWM_DECOR_RESIZEH (1L << 2)
347 #define MWM_DECOR_TITLE (1L << 3)
348 #define MWM_DECOR_MENU (1L << 4)
349 #define MWM_DECOR_MINIMIZE (1L << 5)
350 #define MWM_DECOR_MAXIMIZE (1L << 6)
352 #define MWM_INPUT_MODELESS 0
353 #define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
354 #define MWM_INPUT_SYSTEM_MODAL 2
355 #define MWM_INPUT_FULL_APPLICATION_MODAL 3
356 #define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL
358 typedef struct _mwmhints {
359 unsigned int flags;
360 unsigned int functions;
361 unsigned int decorations;
362 int input_mode;
363 unsigned int status;
364 } MWMHints;
366 static QXWindow* openwindow(int posx,int posy,int w,int h,char*winName)
368 int noborder = 0;
369 XTextProperty iname;
370 XTextProperty wname;
372 pthread_mutex_lock(&X.xmutex);
374 if(!initialized) {
375 fprintf(stderr, "Error: XWindows not yet initialized!\n");
376 pthread_mutex_unlock(&X.xmutex);
377 return 0;
380 QXWindow*qx= malloc(sizeof(QXWindow));
381 if(!X.windowring) {
382 qx->next=qx;
383 qx->prev=qx;
384 X.windowring=qx;
385 } else {
386 qx->next=X.windowring;
387 qx->prev=X.windowring->prev;
388 qx->prev->next=qx;
389 X.windowring->prev=qx;
390 X.windowring=qx;
393 char*iconName=winName;
394 qx->x = posx;
395 qx->y = posy;
396 qx->lenx=w;
397 qx->leny=h;
399 qx->mywin=0;
400 qx->mywin=XCreateSimpleWindow(X.d,X.root,posx,posy,qx->lenx,qx->leny,0,X.white,X.black);
402 if(!qx->mywin) {
403 printf("Error: Couldn't create SimpleWindow\n");
404 pthread_mutex_unlock(&X.xmutex);
405 return 0;
407 qx->xwmh=XAllocWMHints();
408 qx->xsh=XAllocSizeHints();
409 qx->xch=XAllocClassHint();
411 qx->xsh->flags=(PPosition|PSize|PMinSize|PMaxSize);
412 qx->xsh->height=qx->xsh->min_height=qx->xsh->max_height=h;
413 qx->xsh->width =qx->xsh->min_width =qx->xsh->max_width =w;
414 qx->xsh->x=0;
415 qx->xsh->y=0;
417 if(!XStringListToTextProperty(&winName, 1, &wname)) {
418 printf("Error: XStringToTextProperty failed\n");
419 pthread_mutex_unlock(&X.xmutex);
420 return 0;
422 if(!XStringListToTextProperty(&iconName, 1, &iname)) {
423 printf("Error: XStringToTextProperty failed\n");
424 pthread_mutex_unlock(&X.xmutex);
425 return 0;
428 XSetWMProperties(X.d,qx->mywin,&wname,&iname,0,0,qx->xsh,qx->xwmh,qx->xch);
430 qx->xgcv.foreground=X.white;
431 qx->xgcv.background=X.black;
432 //qx->gc=XDefaultGC(X.d,qx->mywin);
433 qx->gc=XCreateGC(X.d,qx->mywin,GCForeground|GCBackground,&qx->xgcv);
435 XGetWindowAttributes(X.d,qx->mywin,&qx->xwa);
437 // enable events for close window
438 XChangeProperty(X.d, qx->mywin, X.atom_wm, XA_ATOM, 32, PropModeReplace, (unsigned char *)(&X.atom_wmdelete), 1 );
440 // no border
441 // (This code comes from the project xine (xine.sourceforge.net)
442 // I wonder if this works with all windowmanagers, though)
443 if(noborder>0)
445 Atom atomprop = XInternAtom(X.d, "_MOTIF_WM_HINTS", True);
446 if(atomprop)
448 MWMHints mwmhints;
449 mwmhints.flags = MWM_HINTS_DECORATIONS;
450 if(noborder==1) mwmhints.decorations = 2;
451 if(noborder>1) mwmhints.decorations = 0;
452 XChangeProperty(X.d, qx->mywin, atomprop, atomprop, 32,
453 PropModeReplace, (unsigned char *) &mwmhints, 5);
454 XSetTransientForHint (X.d, qx->mywin, X.root);
458 qx->bpp=qx->xwa.depth;
459 if(qx->bpp==24) qx->bypp=4; //Can this be 3, also?
460 if(qx->bpp==16) qx->bypp=2;
461 if(qx->bpp==8) qx->bypp=1;
463 #ifdef USE_SHM
464 XShmSegmentInfo segInfo;
465 int bpl = qx->lenx*qx->bypp;
466 segInfo.readOnly = 0;
467 segInfo.shmid = shmget(IPC_PRIVATE,qx->leny*bpl,IPC_CREAT|0777);
468 struct shmid_ds buf;
469 if (segInfo.shmid <0) {
470 perror("shmget");
471 fprintf(stderr,"Size = %d x %d\n", qx->lenx, qx->leny);
473 segInfo.shmaddr = (char*)shmat (segInfo.shmid, 0, 0);
474 if ((long)segInfo.shmaddr == -1) {
475 perror("shmat");
477 XShmAttach(X.d, &segInfo);
478 if (shmctl(segInfo.shmid, IPC_RMID, &buf) < 0)
479 perror("shmctl");
481 qx->currentscr = (U8*)segInfo.shmaddr;
483 # ifdef USE_PIXMAP
484 qx->offscreen_pixmap = XShmCreatePixmap(X.d,qx->mywin,segInfo.shmaddr,&segInfo,qx->lenx,qx->leny,DefaultDepth(X.d, DefaultScreen(X.d)));
485 # else
486 qx->offscreen_ximage = XShmCreateImage(X.d,X.v,24,ZPixmap,(char*)segInfo.shmaddr, &segInfo, qx->lenx,qx->leny);
487 XInitImage(qx->offscreen_ximage);
488 # endif
490 #else
492 qx->currentscr = malloc(qx->lenx*qx->leny*4);
493 # ifdef USE_PIXMAP
494 qx->offscreen_pixmap = XCreatePixmapFromBitmapData(X.d,qx->mywin,qx->currentscr,qx->lenx,qx->leny,0,0,DefaultDepth(X.d,X.s));
495 # else
496 qx->offscreen_ximage = XCreateImage(X.d,X.v,24,ZPixmap,0,(char*)qx->currentscr,qx->lenx,qx->leny,8,qx->lenx*4);
497 XInitImage(qx->offscreen_ximage);
498 # endif
500 #endif
501 XSync(X.d, False);
503 /* get the image data for the area this window will be/is placed on */
505 Window tmpwin;
506 XImage*background;
507 int x,y;
508 XTranslateCoordinates(X.d,qx->mywin,X.root,0,0,&x,&y,&tmpwin);
509 qx->background = XGetImage(X.d, DefaultRootWindow(X.d), x, y, qx->lenx, qx->leny, AllPlanes, ZPixmap);
510 printf("%d %d\n",x,y);
513 XMapRaised(X.d,qx->mywin);
514 XFlush(X.d);
516 qx->xswa.event_mask=(qx->xwa.your_event_mask|=
517 ButtonPressMask|
518 ButtonReleaseMask|
519 //ExposureMask|
520 KeyPressMask|
521 MotionNotify|
522 EnterWindowMask|
523 LeaveWindowMask|
524 PointerMotionMask
526 XChangeWindowAttributes(X.d,qx->mywin,CWEventMask,&qx->xswa);
528 qx->queue = queue_init(sizeof(gfxevent_t), 256);
530 pthread_mutex_unlock(&X.xmutex);
532 pthread_mutex_init(&qx->wmutex, 0);
533 return qx;
536 static void closeWindow(QXWindow*qx)
538 if(qx->mywin) {
539 pthread_mutex_lock(&X.xmutex);
540 XDestroyWindow(X.d,qx->mywin);
541 pthread_mutex_unlock(&X.xmutex);
542 qx->mywin = 0;
546 static void processEvent(gfxevent_t*event)
548 fd_set fdset;
549 struct timeval de;
550 int status;
552 XEvent xe;
554 FD_ZERO(&fdset);
555 FD_SET(ConnectionNumber(X.d),&fdset);
556 de.tv_sec = 0;
557 de.tv_usec = 5000; // 1/200 s
559 pthread_mutex_lock(&X.xmutex);
560 FD_ZERO(&fdset);
561 FD_SET(ConnectionNumber(X.d),&fdset);
562 de.tv_sec = de.tv_usec = 0;
563 if(!select(ConnectionNumber(X.d)+1, &fdset, 0, 0, &de)) {
564 pthread_mutex_unlock(&X.xmutex);
565 usleep(1000);
566 return;
568 XNextEvent(X.d,&xe);
569 pthread_mutex_unlock(&X.xmutex);
571 /* 1: find out which windows the message is for */
572 Window w = 0;
573 switch(xe.type)
575 case ClientMessage: w = xe.xclient.window;break;
576 case Expose: w = xe.xexpose.window;break;
577 case NoExpose: w = xe.xexpose.window;break;
578 case ButtonPress: w = xe.xbutton.window;break;
579 case ButtonRelease: w = xe.xbutton.window;break;
580 case KeyPress: w = xe.xkey.window; break;
581 case KeyRelease: w = xe.xkey.window; break;
582 case MotionNotify: w = xe.xmotion.window;break;
583 case EnterNotify: w = xe.xmotion.window;break;
584 case LeaveNotify: w = xe.xmotion.window;break;
585 default:
586 /* this usually happens for unknown events which
587 we don't care about */
588 return;
591 QXWindow*qx=X.windowring;
592 QXWindow*win=0;
593 event->internal = 0;
594 do {
595 if(w == qx->mywin) {
596 win = qx;
599 while(qx!=X.windowring);
601 if(!win) {
602 /* Not one of our windows. This may be a bug */
603 return;
605 event->internal = win;
607 /* 2: Go for the event construction */
609 switch(xe.type)
611 case ButtonPress:
612 event->type = GFXEVENT_MOUSEPRESS;
613 event->button = xe.xbutton.button;
614 break;
615 case ButtonRelease:
616 event->type = GFXEVENT_MOUSERELEASE;
617 event->button = xe.xbutton.button;
618 break;
619 case KeyPress:
620 event->type = GFXEVENT_KEYPRESS;
621 event->key = xe.xkey.keycode;
622 break;
623 case KeyRelease:
624 event->type = GFXEVENT_KEYRELEASE;
625 event->key = xe.xkey.keycode;
626 break;
627 case MotionNotify:
628 event->type = GFXEVENT_MOUSEMOVE;
629 pthread_mutex_lock(&qx->wmutex);
630 event->x = xe.xmotion.x_root - win->x;
631 event->y = xe.xmotion.y_root - win->y;
632 if(!queue_put(win->queue, event)) {
633 printf("Queue overflow for window %08x!\n", win);
635 pthread_mutex_unlock(&qx->wmutex);
636 break;
637 case EnterNotify:
638 event->type = GFXEVENT_MOUSEENTER;
639 pthread_mutex_lock(&qx->wmutex);
640 event->x = xe.xmotion.x_root - win->x;
641 event->y = xe.xmotion.y_root - win->y;
642 pthread_mutex_unlock(&qx->wmutex);
643 break;
644 case LeaveNotify:
645 event->type = GFXEVENT_MOUSELEAVE;
646 pthread_mutex_lock(&qx->wmutex);
647 event->x = xe.xmotion.x - win->x;
648 event->y = xe.xmotion.y - win->y;
649 pthread_mutex_unlock(&qx->wmutex);
650 break;
651 case ClientMessage:
652 if ((xe.xclient.message_type == X.atom_wm ) &&
653 ((unsigned)xe.xclient.data.l[0] == X.atom_wmdelete) ) {
654 pthread_mutex_lock(&qx->wmutex);
655 closeWindow(win);
656 event->type = GFXEVENT_DESTROY;
657 pthread_mutex_unlock(&qx->wmutex);
659 break;
663 static void*eventloop(void*r)
665 //while(!XEventsQueued(X.d,QueuedAfterReading))
666 while(X.running)
668 gfxevent_t event;
669 event.type = GFXEVENT_NOTHING;
670 event.key = event.x = event.y = event.button = -1;
671 processEvent(&event);
672 if(event.type != GFXEVENT_NOTHING && event.type != GFXEVENT_MOUSEMOVE) {
673 QXWindow*win = (QXWindow*)event.internal;
674 pthread_mutex_lock(&win->wmutex);
675 if(!queue_put(win->queue,&event)) {
676 fprintf(stderr, "Queue overflow for window %08x!\n", win);
678 pthread_mutex_unlock(&win->wmutex);
681 return 0;
684 typedef struct _internal {
685 GC gc;
686 char*name;
687 QXWindow*qx;
688 int lenx, leny;
689 int tmplenx, tmpleny;
690 void*currentscr2;
691 } internal_t;
693 static void gfxwindow_on(gfxwindow_t*win)
695 internal_t*i = (internal_t*)win->internal;
697 i->qx=openwindow(64, 64, win->width, win->height, i->name);
698 if(!i->qx)
699 return;
700 i->currentscr2=0;
701 if(i->qx->bypp != 4) {
702 fprintf(stderr, "Warning: Not a native 32 bit screen, using second buffer\n");
703 i->currentscr2 = malloc(win->width*win->height*4);
704 win->currentscr = (unsigned char*)i->currentscr2;
705 } else {
706 win->currentscr = i->qx->currentscr;
708 win->lastscr = 0;
711 static void gfxwindow_off(gfxwindow_t*win)
713 internal_t*i = (internal_t*)win->internal;
714 if(i->currentscr2)
715 free(i->currentscr2);
716 closeWindow(i->qx);
719 static void gfxwindow_flippage(gfxwindow_t*win)
721 internal_t*i = (internal_t*)win->internal;
722 pthread_mutex_lock(&X.xmutex);
724 if(i->currentscr2) {
725 if(i->qx->bypp==2 && X.isnative16) {
726 int t;
727 int l = win->width*win->height;
728 unsigned char*dest = i->qx->currentscr;
729 unsigned char*src = (unsigned char*)i->currentscr2;
730 do {
731 dest[1] = (src[2]&0xf8)|(src[1]>>5);
732 dest[0] = ((src[1]<<5)&0xe0)|(src[0]>>3);
733 dest+=2;
734 src+=4;
735 } while(--l);
736 } else {
737 memcpy(i->qx->currentscr, i->currentscr2, i->lenx*i->leny*i->qx->bypp);
741 XSetFunction(X.d,i->qx->gc,GXcopy);
742 #ifdef USE_PIXMAP
743 # ifndef USE_SHM
744 if(i->qx->offscreen_pixmap) {
745 XFreePixmap(X.d,i->qx->offscreen_pixmap);i->qx->offscreen_pixmap = 0;
747 i->qx->offscreen_pixmap = XCreatePixmapFromBitmapData(X.d,i->qx->mywin,i->qx->currentscr,i->qx->lenx,i->qx->leny,X.white,X.black,DefaultDepth(X.d,X.s));
748 # endif
749 XCopyArea(X.d,i->qx->offscreen_pixmap,i->qx->mywin,i->qx->gc, 0, 0, i->qx->lenx,i->qx->leny, 0, 0);
750 XFlush(X.d);
751 #else
752 XPutImage(X.d,i->qx->mywin,i->qx->gc,i->qx->offscreen_ximage,0,0,0,0,i->qx->lenx,i->qx->leny);
753 #endif
754 pthread_mutex_unlock(&X.xmutex);
757 void gfxwindow_setcolor(gfxwindow_t*win, U32 c)
759 internal_t*i = (internal_t*)win->internal;
760 pthread_mutex_lock(&X.xmutex);
761 i->qx->xgcv.foreground=getColorFromRGB((U8)(c>>16),(U8)(c>>8),(U8)c);
762 i->gc=XCreateGC(X.d,i->qx->mywin,GCForeground|GCBackground,&i->qx->xgcv);
763 pthread_mutex_unlock(&X.xmutex);
765 void gfxwindow_putpixel(gfxwindow_t*win, int x, int y, unsigned char c)
767 internal_t*i = (internal_t*)win->internal;
768 if(((U32)x)<(U32)win->width && ((U32)y)<(U32)win->height)
769 *(U32*)&win->currentscr[y*win->width*i->qx->bypp+x*i->qx->bypp]=c;
771 static gfxevent_t gfxwindow_getEvent(gfxwindow_t*win)
773 internal_t*i = (internal_t*)win->internal;
774 gfxevent_t event;
775 pthread_mutex_lock(&i->qx->wmutex);
776 if(!i->qx->queue || !queue_get(i->qx->queue,&event)) {
777 event.type = GFXEVENT_NOTHING;
778 } else if(event.type == GFXEVENT_DESTROY) {
779 queue_destroy(i->qx->queue);i->qx->queue=0;
781 pthread_mutex_unlock(&i->qx->wmutex);
782 return event;
785 static void gfxwindow_move(gfxwindow_t*win, int x,int y)
787 internal_t*i = (internal_t*)win->internal;
788 pthread_mutex_lock(&i->qx->wmutex);
789 pthread_mutex_lock(&X.xmutex);
790 XWindowAttributes a;
791 i->qx->x += x;
792 i->qx->y += y;
793 XMoveResizeWindow(X.d, i->qx->mywin, i->qx->x, i->qx->y, i->tmplenx, i->tmpleny);
795 queue_t* queue2 = queue_init(sizeof(gfxevent_t), 256);
796 gfxevent_t event;
797 /* HACK: now that we have moved the window, all mouse move events
798 are outdated- remove them*/
799 while(queue_get(i->qx->queue, &event)) {
800 if(event.type!=GFXEVENT_MOUSEMOVE)
801 queue_put(queue2, &event);
803 queue_destroy(i->qx->queue);
804 i->qx->queue = queue2;
806 pthread_mutex_unlock(&X.xmutex);
807 pthread_mutex_unlock(&i->qx->wmutex);
810 static void gfxwindow_resize(gfxwindow_t*win, int x,int y)
812 internal_t*i = (internal_t*)win->internal;
813 if(x>win->width || y>win->height) {
814 fprintf(stderr, "resize: can only make windows smaller\n");
815 return;
817 if(x<1) x=1;
818 if(y<1) y=1;
819 pthread_mutex_lock(&i->qx->wmutex);
820 i->tmplenx=x;
821 i->tmpleny=y;
822 pthread_mutex_lock(&X.xmutex);
823 XMoveResizeWindow(X.d, i->qx->mywin, i->qx->x, i->qx->y, i->tmplenx, i->tmpleny);
824 pthread_mutex_unlock(&X.xmutex);
825 pthread_mutex_unlock(&i->qx->wmutex);
827 static void gfxwindow_destroy(gfxwindow_t*win)
829 internal_t*i = (internal_t*)win->internal;
830 gfxwindow_off(win);
831 pthread_mutex_destroy(&i->qx->wmutex);
834 gfxwindow_t* gfxwindow_new(int width, int height)
836 gfxwindow_t*w = (gfxwindow_t*)malloc(sizeof(gfxwindow_t));
837 if(!initializexwindows()) {
838 fprintf(stderr, "Warning: Couldn't initialize X-Windows\n");
840 internal_t*i = malloc(sizeof(internal_t));
841 w->internal = i;
842 w->move = gfxwindow_move;
843 w->resize = gfxwindow_resize;
844 w->flippage = gfxwindow_flippage;
845 w->getEvent = gfxwindow_getEvent;
846 w->width = width;
847 w->height = height;
848 w->destroy = gfxwindow_destroy;
850 i->lenx = i->tmplenx = width;
851 i->leny = i->tmpleny = height;
852 i->name = "";
854 gfxwindow_on(w);
855 return w;