cell: checkpoint: more work in emit_function_call()
[mesa.git] / src / glut / fbdev / fbdev.c
index fcbd4f8da280233b345b5138352e1b46af2414ff..80237f5bc750745e5d820d9adb282870bef596e2 100644 (file)
@@ -22,6 +22,9 @@
  * Library for glut using mesa fbdev driver
  *
  * Written by Sean D'Epagnier (c) 2006
+ * 
+ * To improve on this library, maybe support subwindows or overlays,
+ * I (sean at depagnier dot com) will do my best to help.
  */
 
 #include <errno.h>
 #include <linux/vt.h>
 
 #include <GL/gl.h>
-#include <GL/glfbdev.h>
 #include <GL/glut.h>
 
 #include "internal.h"
 
 #define FBMODES "/etc/fb.modes"
 
-
 struct fb_fix_screeninfo FixedInfo;
-struct fb_var_screeninfo VarInfo, OrigVarInfo;
+struct fb_var_screeninfo VarInfo;
+static struct fb_var_screeninfo OrigVarInfo;
 
 static int DesiredDepth = 0;
 
@@ -64,24 +66,21 @@ struct GlutTimer *GlutTimers = NULL;
 struct timeval StartTime;
 
 /* per window data */
-static GLFBDevContextPtr Context;
-static GLFBDevBufferPtr Buffer;
-static GLFBDevVisualPtr Visual;
+GLFBDevContextPtr Context;
+GLFBDevBufferPtr Buffer;
+GLFBDevVisualPtr Visual;
 
 int Redisplay;
 int Visible;
 int VisibleSwitch;
 int Active;
+static int Resized;
 /* we have to poll to see if we are visible
    on a framebuffer that is not active */
 int VisiblePoll;
+int Swapping, VTSwitch;
 static int FramebufferIndex;
 
-static int RequiredWidth;
-static int RequiredHeight;
-static int InitialWidthHint;
-static int InitialHeightHint;
-
 static int Initialized;
 
 char exiterror[256];
@@ -105,26 +104,34 @@ void TestVisible(void) {
 
 static void Cleanup(void)
 {
+   /* do not handle this signal when cleaning up */
+   signal(SIGWINCH, SIG_IGN);
+
+   if(GameMode)
+      glutLeaveGameMode();
+
    if(ConsoleFD != -1)
       RestoreVT();
 
    /* close mouse */
    CloseMouse();
 
-   glFBDevMakeCurrent( NULL, NULL, NULL);
-
-   glFBDevDestroyContext(Context);
-   glFBDevDestroyBuffer(Buffer);
-   glFBDevDestroyVisual(Visual);
+   if(Visual)
+      glutDestroyWindow(1);
 
    /* restore original variable screen info */
    if(FrameBufferFD != -1) {
+      OrigVarInfo.xoffset = 0;
+      OrigVarInfo.yoffset = 0;
+
       if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &OrigVarInfo))
         fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
                 strerror(errno));
 
-      munmap(FrameBuffer, FixedInfo.smem_len);
+      if(FrameBuffer)
+         munmap(FrameBuffer, FixedInfo.smem_len);
       close(FrameBufferFD);
+
    }
 
    /* free allocated back buffer */
@@ -136,7 +143,7 @@ static void Cleanup(void)
 
    if(exiterror[0])
       fprintf(stderr, "[glfbdev glut] %s", exiterror);
-}
+ }
 
 static void CrashHandler(int sig)
 {
@@ -162,10 +169,12 @@ static void removeArgs(int *argcp, char **argv, int num)
 
 void glutInit (int *argcp, char **argv)
 {
-   int i;
-   int nomouse = 0;
-   int nokeyboard = 0;
-   int usestdin = 0;
+   int i, nomouse = 0, nokeyboard = 0, usestdin = 0;
+   int RequiredWidth = 0, RequiredHeight;
+   char *fbdev;
+
+   stack_t stack;
+   struct sigaction sa;
 
    /* parse out args */
    for (i = 1; i < *argcp;) {
@@ -233,15 +242,83 @@ void glutInit (int *argcp, char **argv)
    gettimeofday(&StartTime, 0);
    atexit(Cleanup);
 
-   signal(SIGSEGV, CrashHandler);
+   /* set up SIGSEGV to use alternate stack */
+   stack.ss_flags = 0;
+   stack.ss_size = SIGSTKSZ;
+   if(!(stack.ss_sp = malloc(SIGSTKSZ)))
+      sprintf(exiterror, "Failed to allocate alternate stack for SIGSEGV!\n");
+
+   sigaltstack(&stack, NULL);
+
+   sa.sa_handler = CrashHandler;
+   sa.sa_flags = SA_ONSTACK;
+   sigemptyset(&sa.sa_mask);
+   sigaction(SIGSEGV, &sa, NULL);
+
    signal(SIGINT, CrashHandler);
    signal(SIGTERM, CrashHandler);
+   signal(SIGABRT, CrashHandler);
 
    if(nomouse == 0)
       InitializeMouse();
    if(nokeyboard == 0)
       InitializeVT(usestdin);
 
+   fbdev = getenv("FRAMEBUFFER");
+   if(fbdev) {
+#ifdef MULTIHEAD
+      if(!sscanf(fbdev, "/dev/fb%d", &FramebufferIndex))
+        if(!sscanf(fbdev, "/dev/fb/%d", &FramebufferIndex))
+           sprintf(exiterror, "Could not determine Framebuffer index!\n");
+#endif
+   } else {
+      static char fb[128];
+      struct fb_con2fbmap confb;
+      int fd = open("/dev/fb0", O_RDWR);
+
+      FramebufferIndex = 0;
+
+      confb.console = CurrentVT;
+      if(ioctl(fd, FBIOGET_CON2FBMAP, &confb) != -1)
+        FramebufferIndex = confb.framebuffer;
+      sprintf(fb, "/dev/fb%d", FramebufferIndex);
+      fbdev = fb;
+      close(fd);
+   }
+
+   /* open the framebuffer device */
+   FrameBufferFD = open(fbdev, O_RDWR);
+   if (FrameBufferFD < 0) {
+      sprintf(exiterror, "Error opening %s: %s\n", fbdev, strerror(errno));
+      exit(0);
+   }
+
+   /* get the fixed screen info */
+   if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
+      sprintf(exiterror, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
+             strerror(errno));
+      exit(0);
+   }
+
+   /* get the variable screen info */
+   if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &OrigVarInfo)) {
+      sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
+             strerror(errno));
+      exit(0);
+   }
+
+   /* operate on a copy */
+   VarInfo = OrigVarInfo;
+
+   /* set the depth, resolution, etc */
+   if(RequiredWidth)
+      if(!ParseFBModes(RequiredWidth, RequiredWidth, RequiredHeight,
+                      RequiredHeight, 0, MAX_VSYNC)) {
+        sprintf(exiterror, "No mode (%dx%d) found in "FBMODES"\n",
+                RequiredWidth, RequiredHeight);
+        exit(0);
+      }
+
    Initialized = 1;
 }
 
@@ -250,29 +327,123 @@ void glutInitDisplayMode (unsigned int mode)
    DisplayMode = mode;
 }
 
+static const char *GetStrVal(const char *p, int *set, int min, int max)
+{
+   char *endptr;
+   int comp = *p, val;
+
+   if(p[1] == '=')
+      p++;
+
+   if(*p == '\0')
+      return p;
+
+   val = strtol(p+1, &endptr, 10);
+
+   if(endptr == p+1)
+      return p;
+
+   switch(comp) {
+   case '!':
+      if(val == min)
+        val = max;
+      else
+        val = min;
+      break;
+   case '<':
+      val = min;
+      break;
+   case '>':
+      val = max;
+      break;
+   }
+
+   if(val < min || val > max) {
+      sprintf(exiterror, "display string value out of range\n");
+      exit(0);
+   }
+
+   *set = val;
+
+   return endptr;
+}
+
+static void SetAttrib(int val, int attr)
+{
+   if(val)
+      DisplayMode |= attr;
+   else
+      DisplayMode &= ~attr;
+}
+
+void glutInitDisplayString(const char *string)
+{
+   const char *p = string;
+   int val;
+   while(*p) {
+      if(*p == ' ')
+        p++;
+      else
+      if(memcmp(p, "acca", 4) == 0) {
+        p = GetStrVal(p+4, &AccumSize, 1, 32);
+        SetAttrib(AccumSize, GLUT_ACCUM);
+      } else
+      if(memcmp(p, "acc", 3) == 0) {
+        p = GetStrVal(p+3, &AccumSize, 1, 32);
+        SetAttrib(AccumSize, GLUT_ACCUM);
+      } else
+      if(memcmp(p, "depth", 5) == 0) {
+        p = GetStrVal(p+5, &DepthSize, 12, 32);
+        SetAttrib(DepthSize, GLUT_DEPTH);
+      } else
+      if(memcmp(p, "double", 6) == 0) {
+        val = 1;
+        p = GetStrVal(p+6, &val, 0, 1);
+        SetAttrib(val, GLUT_DOUBLE);
+      } else
+      if(memcmp(p, "index", 5) == 0) {
+        val = 1;
+        p = GetStrVal(p+5, &val, 0, 1);
+        SetAttrib(val, GLUT_INDEX);
+      } else
+      if(memcmp(p, "stencil", 7) == 0) {
+        p = GetStrVal(p+7, &StencilSize, 0, 1);
+        SetAttrib(StencilSize, GLUT_STENCIL);
+      } else
+      if(memcmp(p, "samples", 7) == 0) {
+        NumSamples = 1;
+        p = GetStrVal(p+7, &NumSamples, 0, 16);
+        SetAttrib(NumSamples, GLUT_MULTISAMPLE);
+      } else
+      if(p = strchr(p, ' '))
+         p++;
+      else
+        break;
+   }
+}
+
 void glutInitWindowPosition (int x, int y)
 {
 }
 
 void glutInitWindowSize (int width, int height)
 {
-   InitialWidthHint = width;
-   InitialHeightHint = height;
 }
 
-
 static void ProcessTimers(void)
 {
-   if(GlutTimers && GlutTimers->time < glutGet(GLUT_ELAPSED_TIME)) {
+   while(GlutTimers && GlutTimers->time <= glutGet(GLUT_ELAPSED_TIME)) {
       struct GlutTimer *timer = GlutTimers;
-      timer->func(timer->value);
       GlutTimers = timer->next;
+      timer->func(timer->value);
       free(timer);
    }
 }
 
 void glutMainLoop(void)
 {
+   int idleiters;
+
    if(ReshapeFunc)
       ReshapeFunc(VarInfo.xres, VarInfo.yres);
 
@@ -292,29 +463,60 @@ void glutMainLoop(void)
 
       if(IdleFunc)
         IdleFunc();
-
+      
       if(VisibleSwitch) {
         VisibleSwitch = 0;
         if(VisibilityFunc)
            VisibilityFunc(Visible ? GLUT_VISIBLE : GLUT_NOT_VISIBLE);
       }
 
+      if(Resized) {
+         SetVideoMode();
+         CreateBuffer();
+
+         if(!glFBDevMakeCurrent( Context, Buffer, Buffer )) {
+            sprintf(exiterror, "Failure to Make Current\n");
+            exit(0);
+         }
+
+         InitializeMenus();
+
+         if(ReshapeFunc)
+            ReshapeFunc(VarInfo.xres, VarInfo.yres);
+
+         Redisplay = 1;
+         Resized = 0;
+      }
+
       if(Visible && Redisplay) {
         Redisplay = 0;
-        if(MouseEnabled)
-           EraseCursor();
+         EraseCursor();
         DisplayFunc();
         if(!(DisplayMode & GLUT_DOUBLE)) {
            if(ActiveMenu)
               DrawMenus();
-           if(MouseEnabled)
-              DrawCursor();
+            DrawCursor();
         }
+         idleiters = 0;
+      } else {
+         /* we sleep if not receiving redisplays, and
+            the main loop is running faster than 2khz */
+
+         static int lasttime;
+         int time = glutGet(GLUT_ELAPSED_TIME);
+         if(time > lasttime) {
+            if(idleiters >= 2)
+               usleep(100);
+
+            idleiters = 0;
+            lasttime = time;
+         }
+         idleiters++;         
       }
    }
 }
 
-static void ParseFBModes(void)
+int ParseFBModes(int minw, int maxw, int minh, int maxh, int minf, int maxf)
 {
    char buf[1024];
    struct fb_var_screeninfo vi = VarInfo;
@@ -322,44 +524,34 @@ static void ParseFBModes(void)
    FILE *fbmodes = fopen(FBMODES, "r");
 
    if(!fbmodes) {
-      sprintf(exiterror, "Warning: could not open "
-             FBMODES" using current mode\n");
-      return;
+      sprintf(exiterror, "Warning: could not open "FBMODES"\n");
+      return 0;
    }
 
-   if(InitialWidthHint == 0 && InitialHeightHint == 0
-      && RequiredWidth == 0)
-      return; /* use current mode */
-
    while(fgets(buf, sizeof buf, fbmodes)) {
       char *c;
-      int v;
+      int v, bpp, freq;
 
       if(!(c = strstr(buf, "geometry")))
         continue;
       v = sscanf(c, "geometry %d %d %d %d %d", &vi.xres, &vi.yres,
-                &vi.xres_virtual, &vi.yres_virtual, &vi.bits_per_pixel);
+                &vi.xres_virtual, &vi.yres_virtual, &bpp);
       if(v != 5)
         continue;
 
-      /* now we have to decide what is best */
-      if(RequiredWidth) {
-        if(RequiredWidth != vi.xres || RequiredHeight != vi.yres)
+      if(maxw < minw) {
+        if(maxw < vi.xres && minw > vi.xres)
+           continue;
+      } else
+        if(maxw < vi.xres || minw > vi.xres)
            continue;
-      } else {
-        if(VarInfo.xres < vi.xres && VarInfo.xres < InitialWidthHint)
-           v++;
-        if(VarInfo.xres > vi.xres && vi.xres > InitialWidthHint)
-           v++;
-
-        if(VarInfo.yres < vi.yres && VarInfo.yres < InitialHeightHint)
-           v++;
-        if(VarInfo.yres > vi.yres && vi.yres > InitialHeightHint)
-           v++;
 
-        if(v < 7)
+      if(maxh < minh) {
+        if(maxh < vi.yres && minh > vi.yres)
+           continue;
+      } else
+        if(maxh < vi.yres || minh > vi.yres)
            continue;
-      }
 
       fgets(buf, sizeof buf, fbmodes);
       if(!(c = strstr(buf, "timings")))
@@ -368,111 +560,41 @@ static void ParseFBModes(void)
       v = sscanf(c, "timings %d %d %d %d %d %d %d", &vi.pixclock,
                 &vi.left_margin, &vi.right_margin, &vi.upper_margin,
                 &vi.lower_margin, &vi.hsync_len, &vi.vsync_len);
+
       if(v != 7)
         continue;
 
-      VarInfo = vi; /* finally found a better mode */
-      if(RequiredWidth) {
-        fclose(fbmodes);
-        return;
-      }
+      freq = 1E12/vi.pixclock
+        /(vi.left_margin + vi.xres + vi.right_margin + vi.hsync_len)
+        /(vi.upper_margin + vi.yres + vi.lower_margin + vi.vsync_len);
+
+      if(maxf < minf) {
+        if(maxf < freq && minf > freq)
+           continue;
+      } else
+        if(maxf < freq || minf > freq)
+           continue;
+
+      VarInfo = vi;
+      fclose(fbmodes);
+      return 1;
    }
 
    fclose(fbmodes);
 
-   if(RequiredWidth) {
-      sprintf(exiterror, "No mode (%dx%d) found in "FBMODES"\n",
-             RequiredWidth, RequiredHeight);
-      exit(0);
-   }
+   return 0;
 }
 
-/* ---------- Window Management ----------*/
-int glutCreateWindow (const char *title)
+void SetVideoMode(void)
 {
-   char *fbdev;
-   int attribs[9], i, mask, size;
-
-   if(Initialized == 0) {
-      int argc = 0;
-      char *argv[] = {NULL};
-      glutInit(&argc, argv);
-   }
-
-   if(Context)
-      return 0;
-
-   fbdev = getenv("FRAMEBUFFER");
-   if(fbdev) {
-#ifdef MULTIHEAD
-      if(!sscanf(fbdev, "/dev/fb%d", &FramebufferIndex))
-        if(!sscanf(fbdev, "/dev/fb/%d", &FramebufferIndex))
-           sprintf(exiterror, "Could not determine Framebuffer index!\n");
-#endif
-   } else {
-      static char fb[128];
-      struct fb_con2fbmap confb;
-      int fd = open("/dev/fb0", O_RDWR);
-
-      FramebufferIndex = 0;
-
-      confb.console = CurrentVT;
-      if(ioctl(fd, FBIOGET_CON2FBMAP, &confb) != -1)
-        FramebufferIndex = confb.framebuffer;
-      sprintf(fb, "/dev/fb%d", FramebufferIndex);
-      fbdev = fb;
-      close(fd);
-   }
-
-   /* open the framebuffer device */
-   FrameBufferFD = open(fbdev, O_RDWR);
-   if (FrameBufferFD < 0) {
-      sprintf(exiterror, "Error opening %s: %s\n", fbdev, strerror(errno));
-      exit(0);
-   }
-
-   /* Get the fixed screen info */
-   if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
-      sprintf(exiterror, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
-             strerror(errno));
-      exit(0);
-   }
-
-   /* get the variable screen info */
-   if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &OrigVarInfo)) {
-      sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
-             strerror(errno));
-      exit(0);
-   }
-
-   /* operate on a copy */
-   VarInfo = OrigVarInfo;
-
-   /* set the depth, resolution, etc */
-   ParseFBModes();
-
-   if(DisplayMode & GLUT_INDEX)
-      VarInfo.bits_per_pixel = 8;
-   else
-      if(VarInfo.bits_per_pixel == 8)
-        VarInfo.bits_per_pixel = 32;
-    
-   if (DesiredDepth)
-      VarInfo.bits_per_pixel = DesiredDepth;
-
-   VarInfo.xoffset = 0;
-   VarInfo.yoffset = 0;
-   VarInfo.nonstd = 0;
-   VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
-
    /* set new variable screen info */
    if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &VarInfo)) {
-      sprintf(exiterror, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
-             strerror(errno));
+      sprintf(exiterror, "FBIOPUT_VSCREENINFO failed: %s\n", strerror(errno));
+      strcat(exiterror, "Perhaps the device does not support the selected mode\n");
       exit(0);
    }
 
-   /* reload the screen info to update offsets */
+   /* reload the screen info to update rgb bits */
    if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &VarInfo)) {
       sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
              strerror(errno));
@@ -498,8 +620,16 @@ int glutCreateWindow (const char *title)
 
    /* initialize colormap */
    LoadColorMap();
+}
+
+void CreateBuffer(void)
+{
+   int size = VarInfo.xres_virtual * VarInfo.yres_virtual
+                              * VarInfo.bits_per_pixel / 8;
 
    /* mmap the framebuffer into our address space */
+   if(FrameBuffer)
+      munmap(FrameBuffer, FixedInfo.smem_len);
    FrameBuffer = mmap(0, FixedInfo.smem_len, PROT_READ | PROT_WRITE, 
                      MAP_SHARED, FrameBufferFD, 0);
    if (FrameBuffer == MAP_FAILED) {
@@ -508,8 +638,30 @@ int glutCreateWindow (const char *title)
       exit(0);
    }
 
-   mask = DisplayMode;
-   for(i=0; i<8 && mask; i++) {
+   if(DisplayMode & GLUT_DOUBLE) {
+      free(BackBuffer);
+      if(!(BackBuffer = malloc(size))) {
+        sprintf(exiterror, "Failed to allocate double buffer\n");
+        exit(0);
+      }
+   } else
+      BackBuffer = FrameBuffer;
+
+   if(Buffer)
+      glFBDevDestroyBuffer(Buffer);
+
+   if(!(Buffer = glFBDevCreateBuffer( &FixedInfo, &VarInfo, Visual,
+                                     FrameBuffer, BackBuffer, size))) {
+      sprintf(exiterror, "Failure to create Buffer\n");
+      exit(0);
+   }
+}
+
+void CreateVisual(void)
+{
+   int i, mask = DisplayMode;
+   int attribs[20];
+   for(i=0; i<sizeof(attribs)/sizeof(*attribs) && mask; i++) {
       if(mask & GLUT_DOUBLE) {
         attribs[i] = GLFBDEV_DOUBLE_BUFFER;
         mask &= ~GLUT_DOUBLE;
@@ -549,6 +701,13 @@ int glutCreateWindow (const char *title)
            i--;
            continue;
         }
+
+      if(mask & GLUT_MULTISAMPLE) {
+        attribs[i] = GLFBDEV_MULTISAMPLE;
+        attribs[++i] = NumSamples;
+        mask &= ~GLUT_MULTISAMPLE;
+        continue;
+      }
        
       sprintf(exiterror, "Invalid mode from glutInitDisplayMode\n");
       exit(0);
@@ -560,23 +719,61 @@ int glutCreateWindow (const char *title)
       sprintf(exiterror, "Failure to create Visual\n");
       exit(0);
    }
+}
 
-   size = VarInfo.xres_virtual * VarInfo.yres_virtual
-      * VarInfo.bits_per_pixel / 8;
-   if(DisplayMode & GLUT_DOUBLE) {
-      if(!(BackBuffer = malloc(size))) {
-        sprintf(exiterror, "Failed to allocate double buffer\n");
-        exit(0);
-      }
-   } else
-      BackBuffer = FrameBuffer;
+static void SignalWinch(int arg)
+{
+   /* we can't change bitdepth without destroying the visual */
+   int bits_per_pixel = VarInfo.bits_per_pixel;
+   struct fb_bitfield red = VarInfo.red, green = VarInfo.green,
+                      blue = VarInfo.blue, transp = VarInfo.transp;
 
-   if(!(Buffer = glFBDevCreateBuffer( &FixedInfo, &VarInfo, Visual,
-                                     FrameBuffer, BackBuffer, size))) {
-      sprintf(exiterror, "Failure to create Buffer\n");
+   /* get the variable screen info */
+   if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &VarInfo)) {
+      sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
+             strerror(errno));
       exit(0);
    }
 
+   /* restore bitdepth and color masks only */
+   VarInfo.bits_per_pixel = bits_per_pixel;
+   VarInfo.red = red;
+   VarInfo.green = green;
+   VarInfo.blue = blue;
+   VarInfo.transp = transp;
+
+   Resized = 1;
+}
+
+int glutCreateWindow (const char *title)
+{
+   if(Initialized == 0) {
+      int argc = 0;
+      char *argv[] = {NULL};
+      glutInit(&argc, argv);
+   }
+
+   if(Context)
+      return 0;
+
+   if(DisplayMode & GLUT_INDEX)
+      VarInfo.bits_per_pixel = 8;
+   else
+      if(VarInfo.bits_per_pixel == 8)
+        VarInfo.bits_per_pixel = 32;
+    
+   if (DesiredDepth)
+      VarInfo.bits_per_pixel = DesiredDepth;
+
+   VarInfo.xoffset = 0;
+   VarInfo.yoffset = 0;
+   VarInfo.nonstd = 0;
+   VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
+
+   SetVideoMode();
+   CreateVisual();
+   CreateBuffer();
+
    if(!(Context = glFBDevCreateContext(Visual, NULL))) {
       sprintf(exiterror, "Failure to create Context\n");
       exit(0);
@@ -590,6 +787,10 @@ int glutCreateWindow (const char *title)
    InitializeCursor();
    InitializeMenus();
 
+   glutSetWindowTitle(title);
+
+   signal(SIGWINCH, SignalWinch);
+
    Visible = 1;
    VisibleSwitch = 1;
    Redisplay = 1;
@@ -612,6 +813,12 @@ int glutGetWindow(void)
 
 void glutDestroyWindow(int win)
 {
+   glFBDevMakeCurrent( NULL, NULL, NULL);
+   glFBDevDestroyContext(Context);
+   glFBDevDestroyBuffer(Buffer);
+   glFBDevDestroyVisual(Visual);
+  
+   Visual = NULL;
 }
 
 void glutPostRedisplay(void)
@@ -628,12 +835,24 @@ void glutSwapBuffers(void)
 {
    glFlush();
 
-   if(Visible && DisplayMode & GLUT_DOUBLE) {
-      if(ActiveMenu)
-        DrawMenus();
-      if(MouseEnabled)
-        DrawCursor();
+   if(!(DisplayMode & GLUT_DOUBLE))
+      return;
+
+   if(ActiveMenu)
+      DrawMenus();
+   DrawCursor();
+
+   if(Visible) {
+      Swapping = 1;
       glFBDevSwapBuffers(Buffer);
+      Swapping = 0;
+   }
+
+   /* if there was a vt switch while swapping, switch now */
+   if(VTSwitch) {
+      if(ioctl(ConsoleFD, VT_ACTIVATE, VTSwitch) < 0)
+        sprintf(exiterror, "Error switching console\n");
+      VTSwitch = 0;
    }
 }
 
@@ -643,6 +862,17 @@ void glutPositionWindow(int x, int y)
 
 void glutReshapeWindow(int width, int height)
 {
+   if(GameMode)
+      return;
+
+   if(!ParseFBModes(width, width, height, height, 0, MAX_VSYNC))
+      return;
+
+   signal(SIGWINCH, SIG_IGN);
+
+   SetVideoMode();
+   signal(SIGWINCH, SignalWinch);
+   Resized = 1;
 }
 
 void glutFullScreen(void)
@@ -659,10 +889,12 @@ void glutPushWindow(void)
 
 void glutShowWindow(void)
 {
+   Visible = 1;
 }
 
 void glutHideWindow(void)
 {
+   Visible = 0;
 }
 
 static void UnIconifyWindow(int sig)
@@ -677,6 +909,12 @@ static void UnIconifyWindow(int sig)
              strerror(errno));
       exit(0);
    }
+
+   RestoreColorMap();
+
+   Redisplay = 1;
+   VisibleSwitch = 1;
+   Visible = 1;
 }
 
 void glutIconifyWindow(void)
@@ -686,11 +924,15 @@ void glutIconifyWindow(void)
    if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &OrigVarInfo))
       fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
              strerror(errno));
+
    raise(SIGSTOP);
 }
 
 void glutSetWindowTitle(const char *name)
 {
+   /* escape code to set title in screen */
+   if(getenv("TERM") && memcmp(getenv("TERM"), "screen", 6) == 0)
+      printf("\033k%s\033\\", name);
 }
 
 void glutSetIconTitle(const char *name)