/**
 * TrueReality - output/display/x11/x11.c
 * Copyright (C) 1998, 1999 Niki W. Waibel
 *
 * This program is free software; you can redistribute it and/
 * or modify it under the terms of the GNU General Public Li-
 * cence as published by the Free Software Foundation; either
 * version 2 of the Licence, or any later version.
 *
 * This program is distributed in the hope that it will be use-
 * ful, but WITHOUT ANY WARRANTY; without even the implied war-
 * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public Licence for more details.
 *
 * You should have received a copy of the GNU General Public
 * Licence along with this program; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 * USA.
 *
 * Information about me (the author):
 *   Niki W. Waibel, Reichenau 20, 6890 Lustenau, Austria - EUROPE
 *   niki.waibel@gmx.net
**/





#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <signal.h>
#include <unistd.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

#include <config.h>
#include <parser_extern.h>
#include <type_sizes.h>
#include <memory_extern.h>
#include <dispatch.h>
#include <x11_extern.h>

#include "../display.h"
#include "../sw_renderer.h"
#include "x11.h"

#ifdef DEBUG
        #include <debug.h>
#endif

#ifdef SHM
        #include <sys/ipc.h>
        #include <sys/shm.h>
        #include <X11/extensions/XShm.h>
#endif

#ifdef FPS
#ifdef LINUX   /* FPS - I don't know if this works on other os than linux - please mail */
        #include <sys/time.h>
        #include <unistd.h>
#endif
#endif



/* the following 2 variables are exported in 'include/x11_extern.h' */
Display                         *dsp;
Window                          win;

static Screen                   *scr;
static XWindowAttributes        win_attrib;
XImage                          *img;
static GC                       gc;
static unsigned long            white, black;
static XColor                   color;
XColor                          color6bit[64];
//static XColor                 color8bit[256];   /* by Niki W. Waibel */
static Colormap                 colormap;

static char                     title[] = "TrueReality-" VERSION " by Niki W. Waibel and the help of many others";
static WORD                     width  =   0;   /* initial VI_WIDTH_REG (0x4400008) value */
static WORD                     height =   0;   /* width*3/4 */
static int                      WIDTH  = 640;
static int                      HEIGHT = 480;
#undef DEPTH
static int                      DEPTH;
static int                      REAL_DEPTH;

static void                     *XBuf  = NULL;
static WORD                     flags  = 0;

#ifdef SHM
        static XShmSegmentInfo  XBuf_SHMInfo;
#endif








static  int     InitDisplay();
static  int     DestroyDisplay();

static  void    PrintText(char *text, int x, int y);

#ifdef DEBUG
        static  void PrintDisplayMode(WORD flags);
#endif

static  void    PutImage(int x, int y, int w, int h);

static  void    AllocDisplayMem();
static  void    FreeDisplayMem();










/*******************************************************************************
*                                                                              *
* int OpenVisual()                                                             *
* int CloseVisual()                                                            *
*                                                                              *
********************************************************************************
*                                                                              *
* These routines are used by the emulator to open and to close a visual.       *
*                                                                              *
* Both return a negative int on error and zero on success.                     *
*                                                                              *
*******************************************************************************/





int OpenVisual()
{
        if(InitDisplay() < 0)
                return(-1);

        prefs.display = LOCAL_DISPLAY;

        return(0);

} /* int OpenVisual() */





int CloseVisual()
{
        DestroyDisplay();

        prefs.display = NO_DISPLAY;

        return(0);

} /* int CloseVisual() */










/*******************************************************************************
*                                                                              *
* static int InitDisplay()                                                     *
*                                                                              *
********************************************************************************
*                                                                              *
* This routine is used to initialize the visual.                               *
* It should print serious information of the current status.                   *
* It must NOT be called by the emulator. It's called from 'int OpenVisual()'.  *
* The name is not standard but it should be used!                              *
*                                                                              *
* The routine returns a negative int on error and zero on success.             *
*                                                                              *
*******************************************************************************/





static int InitDisplay()
{
        XSetWindowAttributes    set_win_attrib;
        XEvent                  event;
        int                     i;

#ifdef SHM
        struct shmid_ds         s;
#endif



        printf("Initializing Unix/X display: (most stuff by \"Guenther Sohler\")\n");
   


        printf("Opening display ..."); fflush(stdout);

        dsp = XOpenDisplay(NULL);
        if(!dsp)
        {
                puts(" FAILED\n"); fflush(stdout);
                return(-1);
        }
        
        scr     = DefaultScreenOfDisplay(dsp);
        
        white   = WhitePixelOfScreen(scr);
        black   = BlackPixelOfScreen(scr);
        
        
        printf(" OK\n"
               "Creating window ..."); fflush(stdout);
               
        win = XCreateSimpleWindow(dsp, RootWindowOfScreen(scr), 0, 0, WIDTH, HEIGHT, 0, white, black);
        if(!win)
        {               
                printf(" FAILED\n"); fflush(stdout);
                return(-1);
        }

/* all of the DEPTH stuff is from "Guenther Sohler" <guenther.sohler@newlogic.at> */

        fputs(" OK\n"
              "Checking depth of window ...", stdout); fflush(stdout);

/* Niki W. Waibel: the following does not differ between 24bit and 32bit! */
/* ... but it's ok for 'XCreateImage'                                     */
/* -> we can get the real depth after 'XCreateImage'                      */

        XGetWindowAttributes(dsp, win, &win_attrib);
        DEPTH = win_attrib.depth;

        printf(" %02dbit ... OK\n", DEPTH); fflush(stdout);

        if(DEPTH == 8)
        {
                fputs("With 8 bit we've to allocate 64 colors ...", stdout); fflush(stdout);
                colormap = XCreateColormap(dsp, win, win_attrib.visual, AllocNone);
                XSetWindowColormap(dsp, win, colormap);

                for(i=0; i<64; i++)
                {
                        color.blue  = (i & 0x03) << 14;
                        color.green = (i & 0x0C) << 12;
                        color.red   = (i & 0x30) << 10;
                        if( !XAllocColor(dsp, colormap, &color) )
                        {
                                puts(" FAILED\n"); fflush(stdout);
                                return(-1);
                        }
                        color6bit[i] = color;

                } /* for(i=0; i<64; i++) */
                
                puts(" OK"); fflush(stdout);

        } /* if(DEPTH == 8) */




        {
                XSizeHints      Hints;
                XWMHints        WMHints;



                Hints.flags       = PSize | PMinSize | PMaxSize;
                Hints.min_width   = 32;
                Hints.max_width   = 1280;
                Hints.base_width  = WIDTH;
                Hints.min_height  = 24;
                Hints.max_height  = 1024;
                Hints.base_height = HEIGHT;
                WMHints.input     = True;
                WMHints.flags     = InputHint;

                XSetWMHints(dsp, win, &WMHints);
                XSetWMNormalHints(dsp, win, &Hints);
                XStoreName(dsp, win, title);
        }



/* the following 3 lines are from myself (niki.waibel@gmx.net) */
        set_win_attrib.backing_store = WhenMapped;
        XChangeWindowAttributes(dsp, win, CWBackingStore, &set_win_attrib);
        /* now it looks much nicer when popping up the window ;) */



        /* input events */

        XSelectInput(dsp, win, ButtonPressMask | FocusChangeMask | ExposureMask | KeyPressMask | KeyReleaseMask);



        /* display window */

        fputs("Mapping window ...", stdout); fflush(stdout);

        XMapRaised(dsp, win);

        printf(" OK\n"
               "Clearing window ..."); fflush(stdout);

        XClearWindow(dsp, win);

        /* catch first event to display window */
        XWindowEvent(dsp, win, ExposureMask, &event);



        printf(" OK\n"
               "Creating graphics context ..."); fflush(stdout);

        gc = XCreateGC(dsp, win, 0, 0);



#ifdef SHM   /* this code was first coded by me (Niki W. Waibel) */
             /* then improved by Guenther Sohler (thanks a lot, Gue!) */
        if(prefs.UseSHM)
        {
                printf(" OK\n"
                       "--- SHM stuff ---\n"
                       "Creating image in shared memory ..." ); fflush(stdout);
      
                img = XShmCreateImage(dsp, DefaultVisualOfScreen(scr), DEPTH, ZPixmap, NULL, &XBuf_SHMInfo, WIDTH, HEIGHT);
                if(!img)
                { 
                        puts(" FAILED\n"); fflush(stdout);
                        return(-1);
                }
      
                printf(" OK\n"
                       "Allocating display memory buffer as shared memory ..."); fflush(stdout);
      
                XBuf_SHMInfo.shmid = shmget(IPC_PRIVATE, img->height * img->bytes_per_line, IPC_CREAT | 0777);
      
                if(XBuf_SHMInfo.shmid < 0)
                {
                        puts(" FAILED\n"); fflush(stdout);
                        return(-1);
                }
      
                printf(" OK\n"
                       "Attaching shared memory (shmat) ..."); fflush(stdout);

                XBuf = img->data = XBuf_SHMInfo.shmaddr = shmat(XBuf_SHMInfo.shmid, 0, 0);
                if(!XBuf)
                {
                        puts(" FAILED (shmat)\n"); fflush(stdout);
                        return(-1);
                }

                XBuf_SHMInfo.readOnly = False;
      
                printf(" OK\n"                     
                       "Attaching shared memory (XShmAttach) ..."); fflush(stdout);
      
                if(!XShmAttach(dsp, &XBuf_SHMInfo))
                {
                        puts(" FAILED\n"); fflush(stdout);
                        return(-1); 
                }         

                shmctl(XBuf_SHMInfo.shmid, IPC_RMID, &s);   /* if someone kills me shm should be freed */
             
                puts(" OK\n"
                     "--- end of SHM stuff ---"); fflush(stdout);
        }
        else
#endif
        {
                printf(" OK\n"
                       "Creating image ..." ); fflush(stdout);
      
                img = XCreateImage(dsp, DefaultVisualOfScreen(scr), DEPTH, ZPixmap, 0, XBuf, WIDTH, HEIGHT, DEPTH, 0);
                if(!img)
                { 
                        puts(" FAILED\n"); fflush(stdout);
                        return(-1);
                }
      
                printf(" OK\n"
                       "Allocating display memory buffer ..."); fflush(stdout);

                XBuf = img->data = malloc(img->height * img->bytes_per_line);
                if(!XBuf)
                {
                        puts(" FAILED\n"); fflush(stdout);
                        return(-1);
                }
                puts(" OK"); fflush(stdout);

        }

        fputs("Checking depth of image ...", stdout); fflush(stdout);
        REAL_DEPTH = img->bits_per_pixel;
        printf(" %02dbit ... OK\n", REAL_DEPTH); fflush(stdout);

        if(DEPTH == 15)
                REAL_DEPTH = 15;
        
        printf("-------------------------------------------------------------------------------\n"); fflush(stdout);

        RefreshVisual();

        return(0);
   
} /* static int InitDisplay() */










/*******************************************************************************
*                                                                              *
* static int DestroyDisplay()                                                  *
*                                                                              *
********************************************************************************
*                                                                              *
* This routine is used to destroy the visual.                                  *
* It should print serious information of the current status.                   *
* It must NOT be called by the emulator. It's called from 'int CloseVisual()'. *
* The name is not standard but it should be used!                              *
*                                                                              *
* The routine returns a negative int on error and zero on success.             *
*                                                                              *
*******************************************************************************/





static int DestroyDisplay()
{
        printf("-------------------------------------------------------------------------------\n");

        printf("Destroying Unix/X display:\n");

#ifdef SHM
        if(prefs.UseSHM)
        {
                printf("Detaching shared memory ..."); fflush(stdout);

                XShmDetach(dsp, &XBuf_SHMInfo);
                shmdt(XBuf_SHMInfo.shmaddr);
                free(img);
        }
        else
#endif SHM
        {
                printf("Destroying image ..."); fflush(stdout);
                
                XDestroyImage(img);
        }

        printf(" OK\n"
               "Freeing graphics context ..."); fflush(stdout);

        XFreeGC(dsp, gc);

        printf(" OK\n"
               "Unmapping Window ..."); fflush(stdout);

        XUnmapWindow(dsp, win);

        printf(" OK\n"
          "Destroying Window ..."); fflush(stdout);

        XDestroyWindow(dsp, win);
   
        printf(" OK\n"
          "Closing display ..."); fflush(stdout);

        if(xkeyboardstate.global_auto_repeat == AutoRepeatModeOn)
                XAutoRepeatOn(dsp);
   
        XCloseDisplay(dsp);
        
        printf(" OK\n");
   


        printf("-------------------------------------------------------------------------------\n"); fflush(stdout);

        return(0);

} /* static int DestroyDisplay() */









static void PrintText(char *text, int x, int y)
{
        XSetForeground(dsp, gc, black);
        XDrawString(dsp, win, gc, x+1, y+1, text, strlen(text));
        
        XSetForeground(dsp, gc, white);
        XDrawString(dsp, win, gc, x, y, text, strlen(text));
   
} /* static void PrintText(char *text, int x, int y) */





#ifdef DEBUG

static void PrintDisplayMode(WORD flags)
{
        printf("Displaymode:\n");
   

   
        switch(flags & 0x0003)
        {
            case 0:
                printf("   blank (no data, no sync)\n");
                break;

            case 1:
                printf("   reserved\n");
                break;

            case 2:
                printf("   5/5/5/3 (\"16\" bit)\n");
                break;
         
            case 3:
                printf("   8/8/8/8 (32 bit)\n");
                break;
         
        } /* switch(flags & 0x0003) */
   

   
        if(flags & 0x0004)
                printf("   gamma_dither_enable\n");
        if(flags & 0x0008)
                printf("   gamma_enable\n");
        if(flags & 0x0010)
                printf("   divot_enable\n");
        if(flags & 0x0040)
                printf("   serrate\n");
   

   
        printf("   anti-alias (aa) mode\n");
   
        switch((flags & 0x0300) >> 8)
        {
            case 0:
                printf("      aa & resamp (always fetch extra lines)\n");
                break;

            case 1:
                printf("      aa & resamp (fetch extra lines if needed)\n");
                break;

            case 2:
                printf("      resamp only (treat as all fully covered)\n");
                break;
         
            case 3:
                printf("      neither (replicate pixels, no interpolate)\n");
                break;
         
        } /* switch((flags & 0x0300) >> 8) */
   
} /* static void PrintDisplayMode(WORD flags) */

#endif





void RefreshVisual()
{
        WORD    new_width;
        BYTE    *imsrc1, *imdst1;
        HWORD   *imsrc2, *imdst2;
        WORD    *imsrc4, *imdst4;



#ifdef FPS
#ifdef LINUX   /* FPS - I don't know if this works on other os than linux - please mail */
        static char             fps_text[40];
        int                     fps_update_sec = 1;   /* min update frequency in sec */
                                                      /* otherwise you might not read it properly */
        static long             fps_update = 0;   /* stores the next time for update */
        static int              fps_count = 0;   /* to make fps average */
        static float            fps_rate = 0.0;
        static struct timeval   fps_tv_old  = { 0, 0 };
        struct timeval          fps_tv;
        
#endif
#endif


   
        /* video flags */
   
        flags = ((WORD *)mem.vi_reg)[0];

#ifdef DEBUG
        if(prefs.debug & DBG_DISP_REFRESH)
                puts("DBG_DISP_REFRESH: refresh");
        if(prefs.debug & DBG_DISP_MODE)
                PrintDisplayMode(flags);
#endif
   
   
   
        /* video width */
        /* if width in VI_WIDTH_REG (0x04400008) has changed set windows width */
   
        new_width = ((WORD *)mem.vi_reg)[2];
        if(new_width != width)
        {
                if(new_width < 320 || new_width > 640)
                        width = 640;
                else
                        width = new_width;

                height = (width * 3) >> 2;

                XResizeWindow(dsp, win, width, height);
        }


      
        /* display it! */

        if(new_width >= 320 && new_width <= 640)
        {
                if(flags & 0x0003)
                {
                        XGetWindowAttributes(dsp, win, &win_attrib);
                        if(WIDTH != win_attrib.width || HEIGHT != win_attrib.height)
                        {
                                WIDTH  = win_attrib.width & 0xfffc;
                                HEIGHT = win_attrib.height;

                                /* free all display related memory */
                                FreeDisplayMem();
         

                                /* allocate a new portion of display related memory */
                                AllocDisplayMem();

                        } /* if(WIDTH != win_attrib.width || HEIGHT != win_attib.height) */


         
                        /* source video origin */
                        imsrc4 = (WORD  *) (mem.rd_ram + ((WORD *)mem.vi_reg)[1]);
                        imsrc2 = (HWORD *) imsrc4;
                        imsrc1 = (BYTE  *) imsrc2;
         
                        /* destination video origin */
                        imdst4 = (WORD  *) img->data;
                        imdst2 = (HWORD *) imdst4;
                        imdst1 = (BYTE  *) imdst2;

                        switch(REAL_DEPTH)
                        {
                            case 8:
                                switch(flags & 0x0003)
                                {
                                    case 0:
                                    case 1:
                                        break;
                                    
                                    case 2:   /* local: 2/2/2 (8bit - 6bit used)  n64: 5/5/5/3 (16bit) */
                                 	render_image_16_to_06(imsrc2, imdst1, width, height, WIDTH, HEIGHT);
                                        break;
                                    

                                    case 3:   /* local: 2/2/2 (8bit - 6bit used)   n64: 8/8/8/8 (32bit) */
                                        render_image_32_to_06(imsrc4, imdst1, width, height, WIDTH, HEIGHT);
                                        break;

                                } /* switch(flags & 0x0003) */
                                break;
            
                            case 16:
                                switch(flags & 0x0003)
                                {
                                    case 0:
                                    case 1:
                                        break;

                                    case 2:   /* local: 5/6/5 (16bit)   n64: 5/5/5/3 (16bit) */
                                        render_image_16_to_16(imsrc2, imdst2, width, height, WIDTH, HEIGHT);
                                        break;

                                    case 3:   /* local: 5/6/5 (16bit)   n64: 8/8/8/8 (32bit) */
                                        render_image_32_to_16(imsrc4, imdst2, width, height, WIDTH, HEIGHT);
                                        break;

                                } /* switch(flags & 0x0003) */
                                break;

                            case 15:
                                switch(flags & 0x0003)
                                {
                                    case 0:
                                    case 1:
                                        break;

                                    case 2:   /* local: 5/5/5 (15bit)   n64: 5/5/5/3 (16bit) */
                                        render_image_16_to_15(imsrc2, imdst2, width, height, WIDTH, HEIGHT);
                                        break;

                                    case 3:   /* local: 5/5/5 (15bit)   n64: 8/8/8/8 (32bit) */
                                        render_image_32_to_15(imsrc4, imdst2, width, height, WIDTH, HEIGHT);
                                        break;

                                } /* switch(flags & 0x0003) */
                                break;

                            case 24:
                                switch(flags & 0x0003)
                                {
                                    case 0:
                                    case 1:
                                        break;

                                    case 2:   /* local: 8/8/8 (24bit)   n64: 5/5/5/3 (16bit) */
                                        render_image_16_to_24(imsrc2, imdst1, width, height, WIDTH, HEIGHT);
                                        break;

                                    case 3:   /* local: 8/8/8 (24bit)   n64: 8/8/8/8 (32bit) */
                                        render_image_32_to_24(imsrc4, imdst1, width, height, WIDTH, HEIGHT);
                                        break;

                                } /* switch(flags & 0x0003) */
                                break;

                            case 32:
                                switch(flags & 0x0003)
                                {
                                    case 0:
                                    case 1:
                                        break;

                                    case 2:   /* local: 8/8/8 (32bit)   n64: 5/5/5/3 (16bit) */
                                        render_image_16_to_32(imsrc2, imdst4, width, height, WIDTH, HEIGHT);
                                        break;

                                    case 3:   /* local: 8/8/8 (32bit)   n64: 8/8/8/8 (32bit) */
                                        render_image_32_to_32(imsrc4, imdst4, width, height, WIDTH, HEIGHT);
                                        break;

                                } /* switch(flags & 0x0003) */
                                break;

                            default:
                                fprintf(stderr, "Display depth of %d bit is not supported! (yet ;) )\n", REAL_DEPTH);
                                
                        } /* switch(DEPTH) */
         
                        PutImage(0, 0, WIDTH, HEIGHT);
                }
                else
                {
                        PrintText("DISPLAY: blank (no data, no sync)", 20, 40);
                }
        }
        else
        {
                if(!(flags & 0x0003))
                        PrintText("DISPLAY: blank (no data, no sync)", 20, 40);
         
                PrintText("DISPLAY: wrong width (640 will be used!)", 20, 60);
        }



#ifdef FPS
#ifdef LINUX   /* FPS - I don't know if this works on other os than linux - please mail */

        gettimeofday(&fps_tv, NULL);

        fps_rate = fps_count * fps_rate
                   + 1 / ( ((float)fps_tv.tv_sec     + (float)fps_tv.tv_usec     / 1000000)
                         - ((float)fps_tv_old.tv_sec + (float)fps_tv_old.tv_usec / 1000000) );

        fps_count++;

        fps_rate /= fps_count;
        
        if(fps_update <= fps_tv.tv_sec)
        {
                fps_update = fps_tv.tv_sec + fps_update_sec;
                fps_count  = 0;
                
                if(fps_rate > 99.9)
                        fps_rate = 99.99;
                
                sprintf(fps_text, "%05.2f", fps_rate);

                fps_rate = 0.0;
        }
        
        fps_tv_old.tv_sec = fps_tv.tv_sec;
        fps_tv_old.tv_usec = fps_tv.tv_usec;
        
        PrintText(fps_text, 01, 20);
#endif
#endif
   
        XFlush(dsp);

} /* void RefreshVisual() */





void GetVisualName(char *name, int *n)
{
   strncpy(name, DISPLAYNAME, (size_t) *n);
   
   *n = strlen(DISPLAYNAME);
   
} /* void GetVisualName() */





void SetVisualTitle(char *title)
{
        XStoreName(dsp, win, title);

} /* void SetVisualTitle() */




void SetVisualClipRect(int x, int y, int width, int height)
{
        XRectangle rect[1];



        rect[0].x       = (short)x;
        rect[0].y       = (short)y;
        rect[0].width   = (short)width;
        rect[0].height  = (short)height;

        XSetClipRectangles(dsp, gc, 0, 0, rect, 1, Unsorted);

} /* void SetVisualClipRect() */





void DrawVisualFillRect(int ulx, int uly, int lrx, int lry, int color)
{
        XSetForeground(dsp, gc, (long)color);
        XFillRectangle(dsp, win, gc, ulx, uly, ulx+lrx, uly+lry);
        XFlush(dsp);

} /* void DrawVisualFillRect() */








































static void PutImage(int X, int Y, int W, int H)
{
#ifdef SHM
   if(prefs.UseSHM)
   {
      XShmPutImage(dsp, win, gc, img, X, Y, (WIDTH-W)/2, (HEIGHT-H)/2, W, H, False);
   }
   else
#endif
      XPutImage(dsp, win, gc, img, X, Y, (WIDTH-W)/2, (HEIGHT-H)/2, W, H);
   
} /* static void PutImage(int X, int Y, int W, int H) */





static void FreeDisplayMem()
{
#ifdef SHM
        if(prefs.UseSHM)
        {
                XShmDetach(dsp, &XBuf_SHMInfo);
                shmdt(XBuf_SHMInfo.shmaddr);
                free(img);
        }
        else
#endif
        {
                XDestroyImage(img);
        }
        //fputs("FreeDisplayMem: ready\n", stderr); fflush(stderr);

} /* static void FreeDisplayMem() */





static void AllocDisplayMem()
{
#ifdef SHM
        struct shmid_ds s;
#endif



#ifdef SHM   /* this code was first coded by me (Niki W. Waibel) */
             /* then improved by Guenther Sohler (thanks a lot, Gue!) */
        if(prefs.UseSHM)
        {
                img = XShmCreateImage(dsp, DefaultVisualOfScreen(scr), DEPTH, ZPixmap, NULL, &XBuf_SHMInfo, WIDTH, HEIGHT);
                if(!img)
                { 
                        puts("FATAL DISPLAY ERROR: XCreateImage\n\n"); fflush(stdout);
                        exit(1);
                }
      
                XBuf_SHMInfo.shmid = shmget(IPC_PRIVATE, img->height * img->bytes_per_line, IPC_CREAT | 0777);
      
                if(XBuf_SHMInfo.shmid < 0)
                {
                        puts("FATAL DISPLAY ERROR: shmget\n\n"); fflush(stdout);
                        exit(1);
                }
      
                XBuf = img->data = XBuf_SHMInfo.shmaddr = shmat(XBuf_SHMInfo.shmid, 0, 0);
                if(!XBuf)
                {
                        puts("FATAL DISPLAY ERROR: shmat\n\n"); fflush(stdout);
                        exit(1);
                }

                XBuf_SHMInfo.readOnly = False;
      
                if(!XShmAttach(dsp, &XBuf_SHMInfo))
                {
                        puts("FATAL DISPLAY ERROR: XShmAttach\n\n"); fflush(stdout);
                        exit(1);
                }         

                shmctl(XBuf_SHMInfo.shmid, IPC_RMID, &s);   /* if someone kills me shm should be freed */
        }
        else
#endif
        {
                img = XCreateImage(dsp, DefaultVisualOfScreen(scr), DEPTH, ZPixmap, 0, XBuf, WIDTH, HEIGHT, DEPTH, 0);
                if(!img)
                { 
                        puts("FATAL DISPLAY ERROR: XCreateImage\n\n"); fflush(stdout);
                        exit(1);
                }

                XBuf = img->data = malloc(img->height * img->bytes_per_line);
                if(!XBuf)
                {
                        puts("FATAL DISPLAY ERROR: malloc\n\n"); fflush(stdout);
                        exit(1);
                }

        }

} /* static void AllocDisplayMem() */

