misc
[xonotic/netradiant.git] / radiant / gtkmisc.cpp
index 0ab5905295405de4410941bc0d80326616fe8afe..bf1731996ffa88191036cfa50d68a19a19e14f81 100644 (file)
-/*\r
-Copyright (c) 2001, Loki software, inc.\r
-All rights reserved.\r
-\r
-Redistribution and use in source and binary forms, with or without modification, \r
-are permitted provided that the following conditions are met:\r
-\r
-Redistributions of source code must retain the above copyright notice, this list \r
-of conditions and the following disclaimer.\r
-\r
-Redistributions in binary form must reproduce the above copyright notice, this\r
-list of conditions and the following disclaimer in the documentation and/or\r
-other materials provided with the distribution.\r
-\r
-Neither the name of Loki software nor the names of its contributors may be used \r
-to endorse or promote products derived from this software without specific prior \r
-written permission. \r
-\r
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' \r
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \r
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE \r
-DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY \r
-DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES \r
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; \r
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON \r
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS \r
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \r
-*/\r
-\r
-//\r
-// Small functions to help with GTK\r
-//\r
-\r
-#include <gdk/gdkkeysyms.h>\r
-\r
-#if defined (__linux__) || defined (__APPLE__)\r
-#include <unistd.h>\r
-#endif\r
-\r
-#include <gtk/gtk.h>\r
-\r
-\r
-#ifdef _WIN32\r
-#include <gdk/gdkwin32.h>\r
-#define WIN32_LEAN_AND_MEAN\r
-#include <windows.h>\r
-#endif\r
-\r
-\r
-\r
-#ifdef _WIN32\r
-#include <io.h>\r
-#include <direct.h>\r
-#define R_OK 04\r
-#endif\r
-#include "stdafx.h"\r
-\r
-// =============================================================================\r
-// Misc stuff\r
-\r
-// NOTE TTimo window position saving has always been tricky\r
-//   it doesn't work the same between win32 and linux .. see below that code is fairly different\r
-//   it's also very poorly done, the save calls are a bit randomly disctributed in the OnDestroy\r
-\r
-void save_window_pos (GtkWidget *wnd, window_position_t& pos)\r
-{\r
-  if ((wnd == NULL) || (wnd->window == NULL))\r
-    return;\r
-\r
-  get_window_pos(wnd, &pos.x, &pos.y);\r
-\r
-  pos.w = wnd->allocation.width;\r
-  pos.h = wnd->allocation.height;\r
-\r
-#ifdef DBG_WINDOWPOS\r
-  //Sys_Printf("save_window_pos 'Window %s'\n",buf);\r
-#endif\r
-}\r
-\r
-#ifdef _WIN32\r
-void win32_get_window_pos(GtkWidget *widget, gint *x, gint *y)\r
-{\r
-  // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=913\r
-  if ( g_PrefsDlg.m_bStartOnPrimMon ) {\r
-    RECT rc;\r
-    POINT point;\r
-    HWND xwnd = (HWND)GDK_WINDOW_HWND (widget->window);\r
-    const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect();\r
-\r
-    GetClientRect(xwnd,&rc);\r
-    point.x=rc.left;\r
-    point.y=rc.top;\r
-    ClientToScreen(xwnd,&point);\r
-\r
-    *x=point.x;\r
-    *y=point.y;\r
-\r
-    *x=max(*x,-widget->allocation.width+10);\r
-    *x=min(*x,primaryMonitorRect.width-10);\r
-    *y=max(*y,-widget->allocation.height+10);\r
-    *y=min(*y,primaryMonitorRect.height-10);\r
-  } else {\r
-    // this is the same as the unix version of get_window_pos\r
-    gdk_window_get_root_origin (widget->window, x, y);\r
-  }\r
-#ifdef DBG_WINDOWPOS\r
-  Sys_Printf("win32_get_window_pos %p %d,%d\n",widget,*x,*y);\r
-#endif \r
-}\r
-#endif\r
-\r
-void load_window_pos (GtkWidget *wnd, window_position_t& pos)\r
-{\r
-#ifdef _WIN32\r
-  const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect();\r
-\r
-  if(pos.x < primaryMonitorRect.x\r
-    || pos.y < primaryMonitorRect.y\r
-    || pos.x > primaryMonitorRect.x + primaryMonitorRect.width\r
-    || pos.y > primaryMonitorRect.y + primaryMonitorRect.height)\r
-    gtk_window_set_position(GTK_WINDOW(wnd), GTK_WIN_POS_CENTER_ON_PARENT);\r
-#else\r
-  // FIXME: not multihead safe\r
-  if(pos.x < 0\r
-    || pos.y < 0\r
-    || pos.x > gdk_screen_width ()\r
-    || pos.y > gdk_screen_height ())\r
-    gtk_window_set_position(GTK_WINDOW(wnd), GTK_WIN_POS_CENTER_ON_PARENT);\r
-#endif\r
-  else\r
-    gtk_window_move(GTK_WINDOW(wnd), pos.x, pos.y);\r
-\r
-  gtk_window_set_default_size (GTK_WINDOW (wnd), pos.w, pos.h);\r
-#ifdef DBG_WINDOWPOS\r
-  Sys_Printf("load_window_pos %p 'Window,%s'\n",wnd,windowData);\r
-#endif\r
-}\r
-\r
-gint widget_delete_hide (GtkWidget *widget)\r
-{\r
-  gtk_widget_hide (widget);\r
-\r
-  return TRUE;\r
-}\r
-\r
-\r
-// Thanks to Mercury, Fingolfin - ETG\r
-int readLongLE(FILE *file, unsigned long *m_bytesRead, int *value)\r
-{\r
-  byte buf[4];\r
-  int len = fread(buf, 4, 1, file);\r
-  *m_bytesRead += 4;\r
-  if (len != 1)\r
-    return -1;\r
-\r
-  *value = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;\r
-  return 0;\r
-}\r
-\r
-short readShortLE(FILE *file, unsigned long *m_bytesRead, short unsigned *value)\r
-{\r
-  byte buf[2];\r
-  int len = fread(buf, 2, 1, file);\r
-  *m_bytesRead += 2;\r
-  if (len != 1)\r
-    return -1;\r
-\r
-  *value = buf[0] | buf[1] << 8;\r
-  return 0;\r
-}\r
-\r
-unsigned char *load_bitmap_file (const char* filename, guint16 *width, guint16 *height)\r
-{\r
-  int bmWidth, bmHeight;\r
-  short unsigned bmPlanes, bmBitsPixel;\r
-  typedef struct {\r
-    unsigned char rgbBlue;\r
-    unsigned char rgbGreen;\r
-    unsigned char rgbRed;\r
-    unsigned char rgbReserved;\r
-  } RGBQUAD;\r
-  unsigned char m1,m2;\r
-  int sizeimage;\r
-  short unsigned res1,res2;\r
-  int filesize, pixoff;\r
-  int bmisize, compression;\r
-  int xscale, yscale;\r
-  int colors, impcol;\r
-  unsigned long m_bytesRead = 0;\r
-  unsigned char *imagebits = NULL;\r
-  FILE *fp;\r
-\r
-  *width = *height = 0;\r
-\r
-  fp = fopen(filename,"rb");\r
-  if (fp == NULL)\r
-  {\r
-       return NULL;\r
-  }\r
-\r
-  size_t rc;\r
-  rc = fread(&m1, 1, 1, fp);\r
-  m_bytesRead++;\r
-  if (rc == -1)\r
-  {\r
-      fclose(fp);\r
-      return NULL;\r
-  }\r
-\r
-  rc = fread(&m2, 1, 1, fp);\r
-  m_bytesRead++;\r
-  if ((m1!='B') || (m2!='M'))\r
-  {\r
-      fclose(fp);\r
-      return NULL;\r
-  }\r
-\r
-  if (readLongLE(fp,&m_bytesRead,&filesize)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readShortLE(fp,&m_bytesRead,&res1)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readShortLE(fp,&m_bytesRead,&res2)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readLongLE(fp,&m_bytesRead,&pixoff)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readLongLE(fp,&m_bytesRead,&bmisize)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readLongLE(fp,&m_bytesRead,&bmWidth)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readLongLE(fp,&m_bytesRead,&bmHeight)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readShortLE(fp,&m_bytesRead,&bmPlanes)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readShortLE(fp,&m_bytesRead,&bmBitsPixel)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readLongLE(fp,&m_bytesRead,&compression)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readLongLE(fp,&m_bytesRead,&sizeimage)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readLongLE(fp,&m_bytesRead,&xscale)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readLongLE(fp,&m_bytesRead,&yscale)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readLongLE(fp,&m_bytesRead,&colors)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (readLongLE(fp,&m_bytesRead,&impcol)) {\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  if (colors == 0)\r
-    colors = 1 << bmBitsPixel;\r
-\r
-  RGBQUAD *colormap = NULL;\r
-  if (bmBitsPixel != 24)\r
-  {\r
-       colormap = new RGBQUAD[colors];\r
-       if (colormap == NULL)\r
-       {\r
-         fclose(fp);\r
-         return NULL;\r
-       }\r
-\r
-       int i;\r
-       for (i = 0; i < colors; i++)\r
-       {\r
-         unsigned char r ,g, b, dummy;\r
-\r
-         rc = fread(&b, 1, 1, fp);\r
-         m_bytesRead++;\r
-         if (rc!=1)\r
-         {\r
-               delete [] colormap;\r
-               fclose(fp);\r
-               return NULL;\r
-         }\r
-\r
-         rc = fread(&g, 1, 1, fp); \r
-         m_bytesRead++;\r
-         if (rc!=1)\r
-         {\r
-               delete [] colormap;\r
-               fclose(fp);\r
-               return NULL;\r
-         }\r
-\r
-         rc = fread(&r, 1, 1, fp); \r
-         m_bytesRead++;\r
-         if (rc != 1)\r
-         {\r
-               delete [] colormap;\r
-               fclose(fp);\r
-               return NULL;\r
-         }\r
-\r
-         rc = fread(&dummy, 1, 1, fp); \r
-         m_bytesRead++;\r
-         if (rc != 1)\r
-         {\r
-               delete [] colormap;\r
-               fclose(fp);\r
-               return NULL;\r
-         }\r
-\r
-         colormap[i].rgbRed=r;\r
-         colormap[i].rgbGreen=g;\r
-         colormap[i].rgbBlue=b;\r
-    }\r
-  }\r
-\r
-  if ((long)m_bytesRead > pixoff)\r
-  {\r
-       delete [] colormap;\r
-       fclose(fp);\r
-       return NULL;\r
-  }\r
-\r
-  while ((long)m_bytesRead < pixoff)\r
-  {\r
-       char dummy;\r
-       fread(&dummy,1,1,fp);\r
-       m_bytesRead++;\r
-  }\r
-\r
-  int w = bmWidth;\r
-  int h = bmHeight;\r
-\r
-  // set the output params\r
-  imagebits = (unsigned char *)malloc(w * h * 3);\r
-  long row_size = w * 3;\r
-\r
-  if (imagebits != NULL) \r
-  {\r
-         *width = w;\r
-         *height = h;\r
-         unsigned char *outbuf = imagebits;\r
-         long row = 0;\r
-         long rowOffset = 0;\r
-\r
-         if (compression == 0) // BI_RGB\r
-    {\r
-           // read rows in reverse order\r
-           for (row = bmHeight - 1; row >= 0; row--)\r
-           {\r
-                   // which row are we working on?\r
-                   rowOffset = (long unsigned)row * row_size;                                                \r
-\r
-                   if (bmBitsPixel == 24)\r
-                   {\r
-                     for (int col=0;col<w;col++)\r
-                     {\r
-                           long offset = col * 3;\r
-                           char pixel[3];\r
-\r
-                           if (fread((void *)(pixel),1,3,fp) == 3)\r
-                           {\r
-                             // we swap red and blue here\r
-                             *(outbuf + rowOffset + offset + 0) = pixel[2];  // r\r
-                             *(outbuf + rowOffset + offset + 1) = pixel[1];  // g\r
-                             *(outbuf + rowOffset + offset + 2) = pixel[0];  // b\r
-                           }\r
-              }\r
-                     m_bytesRead += row_size;\r
-\r
-                     // read DWORD padding\r
-                     while ((m_bytesRead - pixoff) & 3)\r
-                     {\r
-                             char dummy;\r
-                             if (fread(&dummy,1,1,fp) != 1)\r
-            {\r
-                         free(imagebits);\r
-                         fclose(fp);\r
-                         return NULL;\r
-            }\r
-                             m_bytesRead++;\r
-          }\r
-        }\r
-        else\r
-        {\r
-                     // pixels are packed as 1 , 4 or 8 bit vals. need to unpack them\r
-                     int bit_count = 0;\r
-                     unsigned long mask = (1 << bmBitsPixel) - 1;\r
-                     unsigned char inbyte = 0;\r
-\r
-                     for (int col = 0; col < w; col++)\r
-          {\r
-                       int pix = 0;\r
-\r
-                       // if we need another byte\r
-                       if (bit_count <= 0)\r
-                             {\r
-                               bit_count = 8;\r
-                               if (fread(&inbyte,1,1,fp) != 1)\r
-                               {\r
-                                       free(imagebits);\r
-                                       delete [] colormap;\r
-                                       fclose(fp);\r
-                                       return NULL;\r
-                               }\r
-                               m_bytesRead++;\r
-                             }\r
-\r
-                             // keep track of where we are in the bytes\r
-                             bit_count -= bmBitsPixel;\r
-                             pix = ( inbyte >> bit_count) & mask;\r
-\r
-                             // lookup the color from the colormap - stuff it in our buffer\r
-                             // swap red and blue\r
-                             *(outbuf + rowOffset + col * 3 + 2) = colormap[pix].rgbBlue;\r
-                             *(outbuf + rowOffset + col * 3 + 1) = colormap[pix].rgbGreen;\r
-                             *(outbuf + rowOffset + col * 3 + 0) = colormap[pix].rgbRed;\r
-          }\r
-\r
-                     // read DWORD padding\r
-                     while ((m_bytesRead - pixoff) & 3)\r
-          {\r
-            char dummy;\r
-            if (fread(&dummy,1,1,fp)!=1)\r
-            {\r
-              free(imagebits);\r
-              if (colormap)\r
-                delete [] colormap;\r
-              fclose(fp);\r
-              return NULL;\r
-            }\r
-            m_bytesRead++;\r
-          }\r
-        }\r
-      }\r
-    }\r
-         else\r
-         {\r
-           int i, x = 0;\r
-           unsigned char c, c1 = 0, *pp;\r
-           row = 0;\r
-           pp = outbuf + (bmHeight - 1) * bmWidth * 3;\r
-    \r
-           if (bmBitsPixel == 8)\r
-           {\r
-                   while (row < bmHeight)\r
-                   {\r
-                     c = getc(fp);\r
-       \r
-                     if (c)\r
-                     {\r
-                             // encoded mode\r
-                             c1 = getc(fp);\r
-                             for (i = 0; i < c; x++, i++)\r
-                             {\r
-                               *pp = colormap[c1].rgbRed; pp++;\r
-                               *pp = colormap[c1].rgbGreen; pp++;\r
-                               *pp = colormap[c1].rgbBlue; pp++;\r
-                             }\r
-                     }\r
-                     else\r
-                     {\r
-                             // c==0x00,  escape codes\r
-                             c = getc(fp);\r
-                             if (c == 0x00) // end of line\r
-                             {\r
-                               row++;\r
-                               x = 0;\r
-                               pp = outbuf + (bmHeight - row - 1) * bmWidth * 3;\r
-                             }\r
-                             else if (c == 0x01)\r
-                               break; // end of pic\r
-                             else if (c == 0x02) // delta\r
-                             {\r
-                               c = getc(fp);\r
-                               x += c;\r
-                               c = getc(fp);\r
-                               row += c;\r
-                               pp = outbuf + x*3 + (bmHeight - row - 1) * bmWidth * 3;\r
-                             }\r
-                             else // absolute mode\r
-                             {\r
-                               for (i = 0; i < c; x++, i++)\r
-                               {\r
-                                       c1 = getc(fp);\r
-                                       *pp = colormap[c1].rgbRed; pp++;\r
-                                       *pp = colormap[c1].rgbGreen; pp++;\r
-                                       *pp = colormap[c1].rgbBlue; pp++;\r
-                               }\r
-        \r
-                               if (c & 1)\r
-                                     getc(fp); // odd length run: read an extra pad byte\r
-                             }\r
-                     }\r
-                   }\r
-           }\r
-           else if (bmBitsPixel == 4)\r
-           {\r
-                   while (row < bmHeight)\r
-                   {\r
-                     c = getc(fp);\r
-      \r
-                     if (c)\r
-                     {\r
-                             // encoded mode\r
-                             c1 = getc(fp);\r
-                             for (i = 0; i < c; x++, i++)\r
-                             {\r
-                               *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++;\r
-                               *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++;\r
-                               *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++;\r
-                             }\r
-                     }\r
-                     else\r
-                     {\r
-                             // c==0x00,  escape codes\r
-                             c = getc(fp);\r
-        \r
-                             if (c == 0x00) // end of line\r
-                             {\r
-                               row++;\r
-                               x = 0;\r
-                               pp = outbuf + (bmHeight - row - 1) * bmWidth * 3;\r
-                             }\r
-                             else if (c == 0x01)\r
-                               break; // end of pic\r
-                             else if (c == 0x02) // delta\r
-                             {\r
-                               c = getc(fp);\r
-                               x += c;\r
-                               c = getc(fp);\r
-                               row += c;\r
-                               pp = outbuf + x * 3 + (bmHeight - row - 1) * bmWidth * 3;\r
-                             }\r
-                             else // absolute mode\r
-                             {\r
-                               for (i = 0; i < c; x++, i++)\r
-                               {\r
-                                       if ((i&1) == 0)\r
-                                         c1 = getc(fp);\r
-                                       *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++;\r
-                                       *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++;\r
-                                       *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++;\r
-                               }\r
-        \r
-                               if (((c & 3) == 1) || ((c & 3) == 2))\r
-                                     getc(fp); // odd length run: read an extra pad byte\r
-            }\r
-          }\r
-                   }\r
-           }\r
-         }\r
-         if (colormap)\r
-           delete [] colormap;\r
-    \r
-         fclose(fp);\r
-  }\r
-  return imagebits;\r
-}\r
-\r
-void bmp_to_pixmap (const char* filename, GdkPixmap **pixmap, GdkBitmap **mask)\r
-{\r
-  guint16 width, height;\r
-  unsigned char *buf;\r
-  GdkWindow *window = gdk_get_default_root_window();\r
-  GdkColormap *colormap;\r
-  GdkGC* gc = gdk_gc_new (window);\r
-  int i, j;\r
-  bool hasMask = false;\r
-\r
-  *pixmap = *mask = NULL;\r
-  buf = load_bitmap_file (filename, &width, &height);\r
-  if (!buf)\r
-    return;\r
-\r
-  colormap = gdk_drawable_get_colormap (window);\r
-  *pixmap = gdk_pixmap_new (window, width, height, -1);\r
-\r
-  typedef struct\r
-  {\r
-    GdkColor c;\r
-    unsigned char *p;\r
-  } PAL;\r
-\r
-  for (i = 0; i < height; i++)\r
-  {\r
-    for (j = 0; j < width; j++)\r
-    {\r
-      unsigned char *p = &buf[(i * width + j) * 3];\r
-      PAL pe;\r
-\r
-      pe.c.red = (gushort)(p[0] * 0xFF);\r
-      pe.c.green = (gushort)(p[1] * 0xFF);\r
-      pe.c.blue = (gushort)(p[2] * 0xFF);\r
-      gdk_colormap_alloc_color(colormap, &pe.c, FALSE, TRUE);\r
-      gdk_gc_set_foreground(gc, &pe.c);\r
-      gdk_draw_point(*pixmap, gc, j, i);\r
-\r
-      if (p[0] == 0xFF && p[1] == 0x00 && p[2] == 0xFF)\r
-        hasMask = true;\r
-    }\r
-  }\r
-\r
-  gdk_gc_unref (gc);\r
-  *mask = gdk_pixmap_new (window, width, height, 1);\r
-  gc = gdk_gc_new (*mask);\r
-  if (hasMask)\r
-  {\r
-    for (i = 0; i < height; i++)\r
-    {\r
-      for (j = 0; j < width; j++)\r
-      {\r
-             GdkColor mask_pattern;\r
-\r
-             // pink is transparent\r
-             if ((buf[(i*width+j)*3] == 0xff) &&\r
-                     (buf[(i*width+j)*3+1] == 0x00) &&\r
-                     (buf[(i*width+j)*3+2] == 0xff))\r
-                     mask_pattern.pixel = 0;\r
-        else\r
-                     mask_pattern.pixel = 1;\r
-\r
-        gdk_gc_set_foreground (gc, &mask_pattern);\r
-        // possible Win32 Gtk bug here\r
-        //gdk_draw_point (*mask, gc, j, i);\r
-        gdk_draw_line (*mask, gc, j, i, j + 1, i);\r
-      }\r
-    }\r
-  }\r
-  else\r
-  {\r
-    GdkColor mask_pattern;\r
-    mask_pattern.pixel = 1;\r
-    gdk_gc_set_foreground (gc, &mask_pattern);\r
-    gdk_draw_rectangle (*mask, gc, 1, 0, 0, width, height);\r
-  }\r
-  gdk_gc_unref(gc);\r
-  free (buf);\r
-}\r
-\r
-void load_pixmap (const char* filename, GtkWidget* widget, GdkPixmap **gdkpixmap, GdkBitmap **mask)\r
-{\r
-  CString str;\r
-\r
-  str = g_strBitmapsPath;\r
-  str += filename;\r
-\r
-  bmp_to_pixmap (str.GetBuffer (), gdkpixmap, mask);\r
-  if (*gdkpixmap == NULL)\r
-  {\r
-    printf("gdkpixmap was null\n");\r
-    char *dummy[] = { "1 1 1 1", "  c None", " " };\r
-    printf("calling gdk_pixmap_create_from_xpm_d\n");\r
-    *gdkpixmap = gdk_pixmap_create_from_xpm_d (gdk_get_default_root_window(), mask, NULL, dummy);\r
-  }\r
-}\r
-\r
-// this is the same as above but used by the plugins\r
-// GdkPixmap **gdkpixmap, GdkBitmap **mask\r
-bool WINAPI load_plugin_bitmap (const char* filename, void **gdkpixmap, void **mask)\r
-{\r
-  CString str;\r
-\r
-  str = g_strGameToolsPath;\r
-  str += g_strPluginsDir;\r
-  str += "bitmaps/";\r
-  str += filename;\r
-  bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask);\r
-\r
-  if (*gdkpixmap == NULL)\r
-  {\r
-    // look in the core plugins\r
-    str = g_strAppPath;\r
-    str += g_strPluginsDir;\r
-    str += "bitmaps/";\r
-    str += filename;\r
-    bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask);\r
-\r
-    if (*gdkpixmap == NULL)\r
-    {\r
-      \r
-      // look in core modules\r
-      str = g_strAppPath;\r
-      str += g_strModulesDir;\r
-      str += "bitmaps/";\r
-      str += filename;\r
-      bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask);\r
-      \r
-      if (*gdkpixmap == NULL)\r
-      {\r
-        char *dummy[] = { "1 1 1 1", "  c None", " " };\r
-        *gdkpixmap = gdk_pixmap_create_from_xpm_d (gdk_get_default_root_window(), (GdkBitmap **)mask, NULL, dummy);\r
-        return false;\r
-      }\r
-    }\r
-  }\r
-  return true;\r
-}\r
-\r
-// Load a xpm file and return a pixmap widget.\r
-GtkWidget* new_pixmap (GtkWidget* widget, char* filename)\r
-{\r
-  GdkPixmap *gdkpixmap;\r
-  GdkBitmap *mask;\r
-  GtkWidget *pixmap;\r
-\r
-  load_pixmap (filename, widget, &gdkpixmap, &mask);\r
-  pixmap = gtk_pixmap_new (gdkpixmap, mask);\r
-\r
-  gdk_drawable_unref (gdkpixmap);\r
-  gdk_drawable_unref (mask);\r
-\r
-  return pixmap;\r
-} \r
-\r
-// =============================================================================\r
-// Menu stuff\r
-\r
-GtkWidget* menu_separator (GtkWidget *menu)\r
-{\r
-  GtkWidget *menu_item = gtk_menu_item_new ();\r
-  gtk_menu_append (GTK_MENU (menu), menu_item);\r
-  gtk_widget_set_sensitive (menu_item, FALSE);\r
-  gtk_widget_show (menu_item);\r
-  return menu_item;\r
-}\r
-\r
-GtkWidget* menu_tearoff (GtkWidget *menu)\r
-{\r
-  GtkWidget *menu_item = gtk_tearoff_menu_item_new ();\r
-  gtk_menu_append (GTK_MENU (menu), menu_item);\r
-// gtk_widget_set_sensitive (menu_item, FALSE); -- controls whether menu is detachable\r
-  gtk_widget_show (menu_item);\r
-  return menu_item;\r
-}\r
\r
-GtkWidget* create_sub_menu_with_mnemonic (GtkWidget *bar, gchar *mnemonic)\r
-{\r
-  GtkWidget *item, *sub_menu;\r
-\r
-  item = gtk_menu_item_new_with_mnemonic (mnemonic);\r
-  gtk_widget_show (item);\r
-  gtk_container_add (GTK_CONTAINER (bar), item);\r
-\r
-  sub_menu = gtk_menu_new ();\r
-  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), sub_menu);\r
-\r
-  return sub_menu;\r
-}\r
-\r
-extern void AddMenuItem (GtkWidget* menu, unsigned int id);\r
-\r
-GtkWidget* create_menu_item_with_mnemonic (GtkWidget *menu, gchar *mnemonic, GtkSignalFunc func, int id)\r
-{\r
-  GtkWidget *item;\r
-\r
-  item = gtk_menu_item_new_with_mnemonic (mnemonic);\r
-\r
-  gtk_widget_show (item);\r
-  gtk_container_add (GTK_CONTAINER (menu), item);\r
-  gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id));\r
-\r
-  AddMenuItem (item, id);\r
-  return item;\r
-}\r
-\r
-GtkWidget* create_check_menu_item_with_mnemonic (GtkWidget *menu, gchar *mnemonic, GtkSignalFunc func, int id, gboolean active)\r
-{\r
-  GtkWidget *item;\r
-\r
-  item = gtk_check_menu_item_new_with_mnemonic(mnemonic);\r
-\r
-  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), active);\r
-  gtk_widget_show (item);\r
-  gtk_container_add (GTK_CONTAINER (menu), item);\r
-  gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id));\r
-\r
-  AddMenuItem (item, id);\r
-  return item;\r
-}\r
-\r
-GtkWidget* create_radio_menu_item_with_mnemonic (GtkWidget *menu, GtkWidget *last, gchar *mnemonic, GtkSignalFunc func, int id, gboolean state)\r
-{\r
-  GtkWidget *item;\r
-  GSList *group = (GSList*)NULL;\r
-\r
-  if (last != NULL)\r
-    group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (last));\r
-  item = gtk_radio_menu_item_new_with_mnemonic (group, mnemonic);\r
-  gtk_check_menu_item_set_state (GTK_CHECK_MENU_ITEM (item), state);\r
-\r
-  gtk_widget_show (item);\r
-  gtk_container_add (GTK_CONTAINER (menu), item);\r
-  gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id));\r
-\r
-  AddMenuItem (item, id);\r
-  return item;\r
-}\r
-\r
-GtkWidget* create_menu_in_menu_with_mnemonic (GtkWidget *menu, const gchar *mnemonic)\r
-{\r
-  GtkWidget *item, *submenu;\r
-\r
-  item = gtk_menu_item_new_with_mnemonic(mnemonic);\r
-  gtk_widget_show (item);\r
-  gtk_container_add (GTK_CONTAINER (menu), item);\r
-\r
-  submenu = gtk_menu_new ();\r
-  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);\r
-\r
-  return submenu;\r
-}\r
-\r
-// =============================================================================\r
-// Message Boxes\r
-\r
-void dialog_button_callback (GtkWidget *widget, gpointer data)\r
-{\r
-  GtkWidget *parent;\r
-  int *loop, *ret;\r
-\r
-  parent = gtk_widget_get_toplevel (widget);\r
-  loop = (int*)g_object_get_data (G_OBJECT (parent), "loop");\r
-  ret = (int*)g_object_get_data (G_OBJECT (parent), "ret");\r
-\r
-  *loop = 0;\r
-  *ret = (int)data;\r
-}\r
-\r
-gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data)\r
-{\r
-  int *loop;\r
-\r
-  gtk_widget_hide (widget);\r
-  loop = (int*)g_object_get_data (G_OBJECT (widget), "loop");\r
-  *loop = 0;\r
-\r
-  return TRUE;\r
-}\r
-\r
-gint dialog_url_callback (GtkWidget *widget, GdkEvent* event, gpointer data)\r
-{\r
-  OpenURL((const char *)g_object_get_data (G_OBJECT (widget), "URL"));\r
-\r
-  return TRUE;\r
-}\r
-\r
-int WINAPI gtk_MessageBox (void *parent, const char* lpText, const char* lpCaption, guint32 uType, const char* URL)\r
-{\r
-  GtkWidget *window, *w, *vbox, *hbox;\r
-  GtkAccelGroup *accel;\r
-  int mode = (uType & MB_TYPEMASK), ret, loop = 1;\r
-\r
-  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);\r
-  gtk_signal_connect (GTK_OBJECT (window), "delete_event",\r
-                      GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);\r
-  gtk_signal_connect (GTK_OBJECT (window), "destroy",\r
-                      GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);\r
-  gtk_window_set_title (GTK_WINDOW (window), lpCaption);\r
-  gtk_container_border_width (GTK_CONTAINER (window), 10);\r
-  g_object_set_data (G_OBJECT (window), "loop", &loop);\r
-  g_object_set_data (G_OBJECT (window), "ret", &ret);\r
-  gtk_widget_realize (window);\r
-\r
-  gtk_window_set_policy(GTK_WINDOW (window),FALSE,FALSE,TRUE);\r
-\r
-  if (parent != NULL)\r
-    gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent));\r
-\r
-  accel = gtk_accel_group_new ();\r
-  gtk_window_add_accel_group (GTK_WINDOW (window), accel);\r
-\r
-  vbox = gtk_vbox_new (FALSE, 10);\r
-  gtk_container_add (GTK_CONTAINER (window), vbox);\r
-  gtk_widget_show (vbox);\r
-\r
-  w = gtk_label_new (lpText);\r
-  gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);\r
-  gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT);\r
-  gtk_widget_show (w);\r
-\r
-  w = gtk_hseparator_new ();\r
-  gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);\r
-  gtk_widget_show (w);\r
-\r
-  hbox = gtk_hbox_new (FALSE, 10);\r
-  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2);\r
-  gtk_widget_show (hbox);\r
\r
-  if (mode == MB_OK)\r
-  {\r
-    w = gtk_button_new_with_label ("Ok");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));\r
-    gtk_widget_add_accelerator (w, "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);\r
-    gtk_widget_add_accelerator (w, "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);\r
-    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);\r
-    gtk_widget_grab_default (w);\r
-    gtk_widget_show (w);\r
-    ret = IDOK;\r
-  }\r
-  else if (mode ==  MB_OKCANCEL)\r
-  {\r
-    w = gtk_button_new_with_label ("Ok");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));\r
-    gtk_widget_add_accelerator (w, "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);\r
-    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);\r
-    gtk_widget_grab_default (w);\r
-    gtk_widget_show (w);\r
-\r
-    w = gtk_button_new_with_label ("Cancel");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));\r
-    gtk_widget_add_accelerator (w, "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);\r
-    gtk_widget_show (w);\r
-    ret = IDCANCEL;\r
-  }\r
-  else if (mode == MB_YESNOCANCEL)\r
-  {\r
-    w = gtk_button_new_with_label ("Yes");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES));\r
-    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);\r
-    gtk_widget_grab_default (w);\r
-    gtk_widget_show (w);\r
\r
-    w = gtk_button_new_with_label ("No");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO));\r
-    gtk_widget_show (w);\r
\r
-    w = gtk_button_new_with_label ("Cancel");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));\r
-    gtk_widget_show (w);\r
-    ret = IDCANCEL;\r
-  }\r
-  else /* if (mode == MB_YESNO) */\r
-  {\r
-    w = gtk_button_new_with_label ("Yes");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES));\r
-    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);\r
-    gtk_widget_grab_default (w);\r
-    gtk_widget_show (w);\r
\r
-    w = gtk_button_new_with_label ("No");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO));\r
-    gtk_widget_show (w);\r
-    ret = IDNO;\r
-  }\r
-\r
-  if (URL)\r
-  {\r
-    w = gtk_button_new_with_label ("Go to URL");\r
-    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);\r
-    gtk_signal_connect (GTK_OBJECT (w), "clicked",\r
-                        GTK_SIGNAL_FUNC (dialog_url_callback), NULL);\r
-    g_object_set_data (G_OBJECT (w), "URL", (void *)URL);\r
-    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);\r
-    gtk_widget_grab_default (w);\r
-    gtk_widget_show (w);\r
-  }\r
-\r
-\r
-  gtk_widget_show (window);\r
-  gtk_grab_add (window);\r
-\r
-  while (loop)\r
-    gtk_main_iteration ();\r
-\r
-  gtk_grab_remove (window);\r
-  gtk_widget_destroy (window);\r
-\r
-  return ret;\r
-}\r
-\r
-// =============================================================================\r
-// File dialog\r
-\r
-// fenris #3078 WHENHELLISFROZENOVER\r
-\r
-//#define FILEDLG_DBG\r
-\r
-static void file_sel_callback (GtkWidget *widget, gpointer data)\r
-{\r
-  GtkWidget *parent;\r
-  int *loop;\r
-  bool *success;\r
-\r
-  parent = gtk_widget_get_toplevel (widget);\r
-  loop = (int*)g_object_get_data (G_OBJECT (parent), "loop");\r
-  success = (bool*)g_object_get_data (G_OBJECT (parent), "success");\r
-  \r
-  if ((int)data == IDOK)\r
-    *success = true;\r
-\r
-#ifdef FILEDLG_DBG\r
-  else\r
-    Sys_Printf("file_sel_callback != IDOK\n");\r
-#endif\r
-  \r
-  *loop = 0;\r
-}\r
-\r
-#ifdef _WIN32\r
-#include <commdlg.h>\r
-static OPENFILENAME ofn;       /* common dialog box structure   */ \r
-static char szDirName[MAX_PATH];    /* directory string              */ \r
-static char szFile[MAX_PATH];       /* filename string               */ \r
-static char szFileTitle[MAX_PATH];  /* file title string             */ \r
-static int i, cbString;        /* integer count variables       */ \r
-static HANDLE hf;              /* file handle                   */ \r
-#else\r
-static char szFile[QER_MAX_NAMELEN];\r
-#endif\r
-\r
-#define FILEDLG_CUSTOM_FILTER_LENGTH 64\r
-// to be used with the advanced file selector\r
-\r
-class CFileType : public IFileTypeList\r
-{\r
-  struct filetype_copy_t\r
-  {\r
-    void operator=(const filetype_t& other)\r
-    {\r
-      m_name = other.name;\r
-      m_pattern = other.pattern;\r
-    }\r
-    string_t m_name;\r
-    string_t m_pattern;\r
-  };\r
-public:\r
-  CFileType()\r
-  {\r
-    m_nTypes = 0;\r
-    m_pTypes = NULL;\r
-    m_strWin32Filters = NULL;\r
-    m_pstrGTKMasks = NULL;\r
-  }\r
-\r
-  virtual ~CFileType()\r
-  {\r
-    delete[] m_pTypes;\r
-    DestroyWin32Filters();\r
-    DestroyGTKMasks();\r
-  }\r
-\r
-  void addType(filetype_t type)\r
-  {\r
-    filetype_copy_t* newTypes = new filetype_copy_t [m_nTypes+1];\r
-    if(m_nTypes > 0)\r
-    {\r
-      for(int i=0; i<m_nTypes; i++)\r
-        newTypes[i] = m_pTypes[i];\r
-      delete[] m_pTypes;\r
-    }\r
-    m_pTypes = newTypes;\r
-    m_pTypes[m_nTypes] = type;\r
-    m_nTypes++;\r
-    ConstructGTKMasks();\r
-    ConstructWin32Filters();\r
-  }\r
\r
-  filetype_t GetTypeForWin32Filter(const char *filter) const\r
-  {\r
-    for(int i=0; i<m_nTypes; i++)\r
-      if(strcmp(m_pTypes[i].m_pattern.c_str(), filter)==0)\r
-        return filetype_t(m_pTypes[i].m_name.c_str(), m_pTypes[i].m_pattern.c_str());\r
-    return filetype_t();\r
-  }\r
-\r
-  filetype_t GetTypeForGTKMask(const char *mask) const\r
-  {\r
-    for(int i=0; i<m_nTypes; i++)\r
-      if(strcmp(m_pstrGTKMasks[i],mask)==0)\r
-        return filetype_t(m_pTypes[i].m_name.c_str(), m_pTypes[i].m_pattern.c_str());\r
-    return filetype_t();\r
-  }\r
-\r
-  char *m_strWin32Filters;\r
-  char **m_pstrGTKMasks;\r
-private:\r
-  int m_nTypes;\r
-  filetype_copy_t *m_pTypes;\r
-\r
-  void DestroyWin32Filters()\r
-  {\r
-    delete[] m_strWin32Filters;\r
-  }\r
-\r
-  void ConstructWin32Filters()\r
-  {\r
-    const char *r;\r
-    char *w;\r
-    int i;\r
-    int len = 0;\r
-    DestroyWin32Filters();\r
-    for(i=0; i<m_nTypes; i++)\r
-      len = len + strlen(m_pTypes[i].m_name.c_str()) + strlen(m_pTypes[i].m_pattern.c_str())*2 + 5;\r
-    m_strWin32Filters = new char[len+1]; // length + null char\r
-    for(i=0, w = m_strWin32Filters; i<m_nTypes; i++)\r
-    {\r
-      for(r = m_pTypes[i].m_name.c_str(); *r!='\0'; r++, w++)\r
-        *w = *r;\r
-      *w++ = ' ';\r
-      *w++ = '(';\r
-      for(r = m_pTypes[i].m_pattern.c_str(); *r!='\0'; r++, w++)\r
-        *w = *r;\r
-      *w++ = ')';\r
-      *w++ = '\0';\r
-      for(r = m_pTypes[i].m_pattern.c_str(); *r!='\0'; r++, w++)\r
-        *w = (*r == ',') ? ';' : *r;\r
-      *w++ = '\0';\r
-    }\r
-    m_strWin32Filters[len] = '\0';\r
-  }\r
-\r
-  void DestroyGTKMasks()\r
-  {\r
-    if(m_pstrGTKMasks != NULL)\r
-      for(char **p = m_pstrGTKMasks; *p != NULL; p++)\r
-        delete[] *p;\r
-    delete[] m_pstrGTKMasks;\r
-  }\r
-  \r
-  void ConstructGTKMasks()\r
-  {\r
-    const char *r;\r
-    char *w;\r
-    int i;\r
-    int len = 0;\r
-    DestroyGTKMasks();\r
-    m_pstrGTKMasks = new char*[m_nTypes+1];\r
-    for(i=0; i<m_nTypes; i++)\r
-    {\r
-      len = strlen(m_pTypes[i].m_name.c_str()) + strlen(m_pTypes[i].m_pattern.c_str()) + 3;\r
-      m_pstrGTKMasks[i] = new char[len+1]; // length + null char\r
-      w = m_pstrGTKMasks[i];\r
-      for(r = m_pTypes[i].m_name.c_str(); *r!='\0'; r++, w++)\r
-        *w = *r;\r
-      *w++ = ' ';\r
-      *w++ = '<';\r
-      for(r = m_pTypes[i].m_pattern.c_str(); *r!='\0'; r++, w++)\r
-        *w = *r;\r
-      *w++ = '>';\r
-      *w++ = '\0';\r
-    }\r
-    m_pstrGTKMasks[m_nTypes] = NULL;\r
-  }\r
-\r
-};\r
-\r
-const char* file_dialog (void *parent, gboolean open, const char* title, const char* path, const char* pattern)\r
-{\r
-  // Gtk dialog\r
-  GtkWidget* file_sel;\r
-  int loop = 1;\r
-  char *new_path = NULL;\r
-\r
-  const char* r;\r
-  char* w;\r
-  filetype_t type;\r
-  CFileType typelist;\r
-  if(pattern != NULL)\r
-    GetFileTypeRegistry()->getTypeList(pattern, &typelist);\r
-\r
-#ifdef FILEDLG_DBG\r
-  Sys_Printf("file_dialog: open = %d title = %s path = %s\n", open, title, path);\r
-  if (pattern)\r
-  {\r
-    Sys_Printf("Patterns:\n");\r
-    char** p = typelist.m_pstrGTKMasks;\r
-    while(*p!=NULL)\r
-      Sys_Printf("%s\n", *p++);\r
-  }\r
-  else\r
-    Sys_Printf("no patterns\n");\r
-#endif\r
-\r
-#ifdef _WIN32\r
-  // win32 dialog stores the selected "save as type" extension in the second null-terminated string\r
-  char customfilter[FILEDLG_CUSTOM_FILTER_LENGTH];\r
-\r
-  if (g_PrefsDlg.m_bNativeGUI)\r
-  {\r
-#ifdef FILEDLG_DBG\r
-    Sys_Printf("Doing win32 file dialog...");\r
-#endif\r
-    // do that the native way\r
-    /* Place the terminating null character in the szFile. */  \r
-    szFile[0] = '\0';\r
-    customfilter[0] = customfilter[1] = customfilter[2] = '\0';\r
-    \r
-    /* Set the members of the OPENFILENAME structure. */     \r
-    ofn.lStructSize = sizeof(OPENFILENAME); \r
-    ofn.hwndOwner = (HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window);\r
-    if (pattern)\r
-    {\r
-      ofn.nFilterIndex = 0;\r
-      ofn.lpstrFilter = typelist.m_strWin32Filters;\r
-    }\r
-    else ofn.nFilterIndex = 1;\r
-    ofn.lpstrCustomFilter = customfilter;\r
-    ofn.nMaxCustFilter = sizeof(customfilter);\r
-    ofn.lpstrFile = szFile;\r
-    ofn.nMaxFile = sizeof(szFile); \r
-    ofn.lpstrFileTitle = NULL; // we don't need to get the name of the file\r
-    if(path)\r
-    {\r
-      // szDirName: Radiant uses unix convention for paths internally\r
-      //   Win32 (of course) and Gtk (who would have thought) expect the '\\' convention\r
-      // copy path, replacing dir separators as appropriate\r
-      for(r=path, w=szDirName; *r!='\0'; r++)\r
-        *w++ = (*r=='/') ? '\\' : *r;\r
-      // terminate string\r
-      *w = '\0';\r
-      ofn.lpstrInitialDir = szDirName;\r
-    }\r
-    else ofn.lpstrInitialDir = NULL;\r
-    ofn.lpstrTitle = title;\r
-    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; \r
-\r
-    /* Display the Open dialog box. */\r
-    // it's open or close depending on 'open' parameter\r
-    if (open)\r
-    {\r
-      if (!GetOpenFileName(&ofn))\r
-        return NULL;   // canceled\r
-    }\r
-    else\r
-    {\r
-      if (!GetSaveFileName(&ofn))\r
-        return NULL;   // canceled\r
-    }\r
-\r
-    if(pattern != NULL)\r
-      type = typelist.GetTypeForWin32Filter(customfilter+1);\r
-    \r
-#ifdef FILEDLG_DBG\r
-    Sys_Printf("Done.\n");\r
-#endif\r
-  }\r
-  else\r
-  {\r
-#endif\r
-    // do that the Gtk way\r
-    if (title == NULL)\r
-      title = open ? "Open File" : "Save File";\r
-    \r
-#ifdef FILEDLG_DBG\r
-    Sys_Printf("Doing Gtk file dialog:\nBuilding new_path..");\r
-#endif\r
-    // we expect an actual path below, if the path is NULL we might crash\r
-    if (!path || path[0] == '\0')\r
-    {\r
-#ifdef _WIN32\r
-      path = "C:\\";\r
-#elif defined (__linux__) || defined (__APPLE__)\r
-      path = "/";\r
-#else\r
-      path = "/";\r
-#endif\r
-    }\r
-\r
-    // alloc new path with extra char for dir separator\r
-    new_path = new char[strlen(path)+1+1];\r
-    // copy path, replacing dir separators as appropriate\r
-    for(r=path, w=new_path; *r!='\0'; r++)\r
-      *w++ = (*r=='/') ? G_DIR_SEPARATOR : *r;\r
-    // add dir separator to end of path if required\r
-    if(*(w-1) != G_DIR_SEPARATOR) *w++ = G_DIR_SEPARATOR;\r
-    // terminate string\r
-    *w = '\0';\r
-\r
-#ifdef FILEDLG_DBG\r
-    Sys_Printf("Done.\n");\r
-    Sys_Printf("Calling gtk_file_selection_new with title: %s...", title);\r
-#endif\r
-\r
-    file_sel = gtk_file_selection_new (title);\r
-\r
-#ifdef FILEDLG_DBG\r
-    Sys_Printf("Done.\n");\r
-    Sys_Printf("Set the masks...");\r
-#endif\r
-\r
-#if 0 //!\todo Add masks to GtkFileSelection in gtk-2.0\r
-    // set the masks\r
-    if (pattern)\r
-    {\r
-      gtk_file_selection_clear_masks (GTK_FILE_SELECTION (file_sel));\r
-      gtk_file_selection_set_masks (GTK_FILE_SELECTION (file_sel), const_cast<const char**>(typelist.m_pstrGTKMasks));\r
-    }\r
-#endif\r
-\r
-#ifdef FILEDLG_DBG\r
-    Sys_Printf("Done.\n");\r
-#endif\r
-\r
-    gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked",\r
-      GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK));\r
-    gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked",\r
-      GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL));\r
-    gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event",\r
-      GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);\r
-    gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel));\r
-    \r
-    if (parent != NULL)\r
-      gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent));\r
-    \r
-#ifdef FILEDLG_DBG\r
-    Sys_Printf("set_data...");\r
-#endif\r
-    bool success = false;\r
-    g_object_set_data (G_OBJECT (file_sel), "loop", &loop);\r
-    g_object_set_data (G_OBJECT (file_sel), "success", &success);\r
-#ifdef FILEDLG_DBG\r
-    Sys_Printf("Done.\n");\r
-#endif\r
-    \r
-    if (!open)\r
-    {\r
-#ifdef FILEDLG_DBG\r
-      Sys_Printf("set_data \"overwrite\" ...");\r
-#endif\r
-      g_object_set_data (G_OBJECT (file_sel), "overwrite", GINT_TO_POINTER (1));\r
-#ifdef FILEDLG_DBG\r
-      Sys_Printf("Done.\n");\r
-#endif\r
-    }\r
-    \r
-    if (new_path != NULL)\r
-    {\r
-#ifdef FILEDLG_DBG\r
-      Sys_Printf("gtk_file_selection_set_filename... %p", file_sel); \r
-#endif\r
-      gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), new_path);\r
-      delete[] new_path;\r
-#ifdef FILEDLG_DBG\r
-      Sys_Printf("Done.\n");\r
-#endif\r
-    }\r
-\r
-    gtk_grab_add (file_sel);\r
-#ifdef FILEDLG_DBG\r
-    Sys_Printf("gtk_widget_show... %p", file_sel); \r
-#endif\r
-    gtk_widget_show (file_sel);\r
-#ifdef FILEDLG_DBG\r
-    Sys_Printf("Done.\n"); \r
-#endif\r
-\r
-#ifdef FILEDLG_DBG\r
-    Sys_Printf("gtk_main_iteration..."); \r
-#endif\r
-    while (loop)\r
-      gtk_main_iteration ();\r
-    if(success)\r
-    {\r
-#if 0 //!\todo Add masks to GtkFileSelection in gtk2\r
-      if(pattern!=NULL)\r
-        type = typelist.GetTypeForGTKMask(GTK_FILE_SELECTION (file_sel)->mask);\r
-#endif\r
-      strcpy(szFile, gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel)));\r
-    }\r
-#ifdef FILEDLG_DBG\r
-    Sys_Printf("Done.\n");\r
-#endif\r
-    \r
-    gtk_grab_remove (file_sel);\r
-    gtk_widget_destroy (file_sel);\r
-#ifdef _WIN32\r
-  }\r
-#endif\r
-\r
-  // don't return an empty filename\r
-  if(szFile[0] == '\0') return NULL;\r
-\r
-  // convert back to unix format\r
-  for(w=szFile; *w!='\0'; w++)\r
-    if(*w=='\\')\r
-      *w = '/';\r
-\r
-#if defined(WIN32)\r
-  if (g_PrefsDlg.m_bNativeGUI) // filetype mask not supported in gtk dialog yet\r
-  {\r
-    // when saving, force an extension depending on filetype\r
-    /* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */\r
-    if(!open && pattern != NULL)\r
-    {\r
-      // last ext separator\r
-      w = strrchr(szFile, '.');\r
-      // no extension\r
-      w = (w!=NULL) ? w : szFile+strlen(szFile);\r
-      strcpy(w, type.pattern+1);\r
-    }\r
-  }\r
-#endif\r
-\r
-  // prompt to overwrite existing files\r
-  if (!open)\r
-    if (access (szFile, R_OK) == 0)\r
-      if (gtk_MessageBox (parent, "File already exists.\nOverwrite?", "GtkRadiant", MB_YESNO) == IDNO)\r
-        return NULL;\r
-\r
-#ifdef FILEDLG_DBG\r
-  // ... let's use a static filename\r
-  Sys_Printf("filename: %p\n", szFile);\r
-#endif\r
-\r
-  return szFile;\r
-}\r
-\r
-char* WINAPI dir_dialog (void *parent, const char* title, const char* path)\r
-{\r
-  GtkWidget* file_sel;\r
-  char* filename = (char*)NULL;\r
-  int loop = 1;\r
-  bool success = false;\r
-\r
-  file_sel = gtk_file_selection_new (title);\r
-  gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked",\r
-                      GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK));\r
-  gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked",\r
-                      GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL));\r
-  gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event",\r
-                      GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);\r
-  gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel));\r
-\r
-  if (parent != NULL)\r
-    gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent));\r
-\r
-  gtk_widget_hide (GTK_FILE_SELECTION (file_sel)->file_list->parent);\r
-\r
-  g_object_set_data (G_OBJECT (file_sel), "loop", &loop);\r
-  g_object_set_data (G_OBJECT (file_sel), "filename", &filename);\r
-  g_object_set_data (G_OBJECT (file_sel), "success", &success);\r
-\r
-  if (path != NULL)\r
-    gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), path);\r
-\r
-  gtk_grab_add (file_sel);\r
-  gtk_widget_show (file_sel);\r
-\r
-  while (loop)\r
-    gtk_main_iteration ();\r
-\r
-  filename = g_strdup(gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel)));\r
-\r
-  gtk_grab_remove (file_sel);\r
-  gtk_widget_destroy (file_sel);\r
-\r
-  return filename;\r
-}\r
-\r
-bool WINAPI color_dialog (void *parent, float *color, const char* title)\r
-{\r
-  GtkWidget* dlg;\r
-  double clr[3];\r
-  int loop = 1, ret = IDCANCEL;\r
-\r
-  clr[0] = color[0];\r
-  clr[1] = color[1];\r
-  clr[2] = color[2];\r
-\r
-  dlg = gtk_color_selection_dialog_new (title);\r
-  gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr);\r
-  gtk_signal_connect (GTK_OBJECT (dlg), "delete_event",\r
-                      GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);\r
-  gtk_signal_connect (GTK_OBJECT (dlg), "destroy",\r
-                      GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);\r
-  gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked",\r
-                     GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));\r
-  gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked",\r
-                     GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));\r
-  g_object_set_data (G_OBJECT (dlg), "loop", &loop);\r
-  g_object_set_data (G_OBJECT (dlg), "ret", &ret);\r
-\r
-  if (parent != NULL)\r
-    gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (parent));\r
-\r
-  gtk_widget_show (dlg);\r
-  gtk_grab_add (dlg);\r
-\r
-  while (loop)\r
-    gtk_main_iteration ();\r
-\r
-  GdkColor gdkcolor;\r
-  gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), &gdkcolor);\r
-  clr[0] = gdkcolor.red / 65535.0;\r
-  clr[1] = gdkcolor.green / 65535.0;\r
-  clr[2] = gdkcolor.blue / 65535.0;\r
-\r
-  gtk_grab_remove (dlg);\r
-  gtk_widget_destroy (dlg);\r
-\r
-  if (ret == IDOK)\r
-  {\r
-    color[0] = (float)clr[0];\r
-    color[1] = (float)clr[1];\r
-    color[2] = (float)clr[2];\r
-\r
-    return true;\r
-  }\r
-\r
-  return false;\r
-}\r
-\r
-void OpenURL(const char *url)\r
-{\r
-  // let's put a little comment\r
-  Sys_Printf("OpenURL: %s\n", url);\r
-#ifdef __linux__\r
-  // \todo FIXME: the way we open URLs on *nix should be improved. A script is good (see how I do on RTCW)\r
-  char command[2*PATH_MAX];\r
-  snprintf( command, sizeof(command), "%s/openurl.sh \"%s\" &", g_strAppPath.GetBuffer(), url );\r
-  if (system (command) != 0)\r
-    gtk_MessageBox (g_pParentWnd->m_pWidget, "Failed to launch Netscape!");\r
-#endif\r
-#ifdef __APPLE__\r
-  char command[2*PATH_MAX];\r
-  snprintf (command, sizeof(command),\r
-            "open \"%s\" &", url, url);\r
-  if (system (command) != 0)\r
-    gtk_MessageBox (g_pParentWnd->m_pWidget, "Unable to launch browser!");\r
-#endif\r
-#ifdef _WIN32\r
-  ShellExecute( (HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window), "open", url, NULL, NULL, SW_SHOW );\r
-#endif\r
-}\r
-\r
-void CheckMenuSplitting (GtkWidget *&menu)\r
-{\r
-  GtkWidget *item,*menu2;\r
-\r
-  GtkRequisition requisition;\r
-  gint screen_height;\r
-\r
-  gtk_widget_size_request (GTK_WIDGET (menu), &requisition);\r
-  screen_height = gdk_screen_height ();\r
-\r
-  if ((screen_height - requisition.height) < 20)\r
-  {\r
-    menu2 = gtk_menu_new ();\r
-\r
-    // move the last 2 items to a submenu (3 because of win32)\r
-    for (int i = 0; i < 3; i++)\r
-    {\r
-      item = GTK_WIDGET (g_list_last (gtk_container_children (GTK_CONTAINER (menu)))->data);\r
-      gtk_widget_ref (item);\r
-      gtk_container_remove (GTK_CONTAINER (menu), item);\r
-      gtk_menu_append (GTK_MENU (menu2), item);\r
-      gtk_widget_unref (item);\r
-    }\r
-\r
-    item = gtk_menu_item_new_with_label ("--------");\r
-    gtk_widget_show (item);\r
-    gtk_container_add (GTK_CONTAINER (menu), item);\r
-    gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu2);\r
-    menu = menu2;\r
-  }\r
-}\r
+/*
+Copyright (c) 2001, Loki software, inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, 
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list 
+of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+Neither the name of Loki software nor the names of its contributors may be used 
+to endorse or promote products derived from this software without specific prior 
+written permission. 
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY 
+DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+*/
+
+//
+// Small functions to help with GTK
+//
+
+#include <gdk/gdkkeysyms.h>
+
+#if defined (__linux__) || defined (__APPLE__)
+#include <unistd.h>
+#endif
+
+#include <gtk/gtk.h>
+
+
+#ifdef _WIN32
+#include <gdk/gdkwin32.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+
+
+#ifdef _WIN32
+#include <io.h>
+#include <direct.h>
+#define R_OK 04
+#endif
+#include "stdafx.h"
+
+// =============================================================================
+// Misc stuff
+
+// NOTE TTimo window position saving has always been tricky
+//   it doesn't work the same between win32 and linux .. see below that code is fairly different
+//   it's also very poorly done, the save calls are a bit randomly disctributed in the OnDestroy
+
+void save_window_pos (GtkWidget *wnd, window_position_t& pos)
+{
+  if ((wnd == NULL) || (wnd->window == NULL))
+    return;
+
+  get_window_pos(wnd, &pos.x, &pos.y);
+
+  pos.w = wnd->allocation.width;
+  pos.h = wnd->allocation.height;
+
+#ifdef DBG_WINDOWPOS
+  //Sys_Printf("save_window_pos 'Window %s'\n",buf);
+#endif
+}
+
+#ifdef _WIN32
+void win32_get_window_pos(GtkWidget *widget, gint *x, gint *y)
+{
+  // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=913
+  if ( g_PrefsDlg.m_bStartOnPrimMon ) {
+    RECT rc;
+    POINT point;
+    HWND xwnd = (HWND)GDK_WINDOW_HWND (widget->window);
+    const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect();
+
+    GetClientRect(xwnd,&rc);
+    point.x=rc.left;
+    point.y=rc.top;
+    ClientToScreen(xwnd,&point);
+
+    *x=point.x;
+    *y=point.y;
+
+    *x=max(*x,-widget->allocation.width+10);
+    *x=min(*x,primaryMonitorRect.width-10);
+    *y=max(*y,-widget->allocation.height+10);
+    *y=min(*y,primaryMonitorRect.height-10);
+  } else {
+    // this is the same as the unix version of get_window_pos
+    gdk_window_get_root_origin (widget->window, x, y);
+  }
+#ifdef DBG_WINDOWPOS
+  Sys_Printf("win32_get_window_pos %p %d,%d\n",widget,*x,*y);
+#endif 
+}
+#endif
+
+void load_window_pos (GtkWidget *wnd, window_position_t& pos)
+{
+#ifdef _WIN32
+  const GdkRectangle primaryMonitorRect = g_pParentWnd->GetPrimaryMonitorRect();
+
+  if(pos.x < primaryMonitorRect.x
+    || pos.y < primaryMonitorRect.y
+    || pos.x > primaryMonitorRect.x + primaryMonitorRect.width
+    || pos.y > primaryMonitorRect.y + primaryMonitorRect.height)
+    gtk_window_set_position(GTK_WINDOW(wnd), GTK_WIN_POS_CENTER_ON_PARENT);
+#else
+  // FIXME: not multihead safe
+  if(pos.x < 0
+    || pos.y < 0
+    || pos.x > gdk_screen_width ()
+    || pos.y > gdk_screen_height ())
+    gtk_window_set_position(GTK_WINDOW(wnd), GTK_WIN_POS_CENTER_ON_PARENT);
+#endif
+  else
+    gtk_window_move(GTK_WINDOW(wnd), pos.x, pos.y);
+
+  gtk_window_set_default_size (GTK_WINDOW (wnd), pos.w, pos.h);
+#ifdef DBG_WINDOWPOS
+  Sys_Printf("load_window_pos %p 'Window,%s'\n",wnd,windowData);
+#endif
+}
+
+gint widget_delete_hide (GtkWidget *widget)
+{
+  gtk_widget_hide (widget);
+
+  return TRUE;
+}
+
+
+// Thanks to Mercury, Fingolfin - ETG
+int readLongLE(FILE *file, unsigned long *m_bytesRead, int *value)
+{
+  byte buf[4];
+  int len = fread(buf, 4, 1, file);
+  *m_bytesRead += 4;
+  if (len != 1)
+    return -1;
+
+  *value = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
+  return 0;
+}
+
+short readShortLE(FILE *file, unsigned long *m_bytesRead, short unsigned *value)
+{
+  byte buf[2];
+  int len = fread(buf, 2, 1, file);
+  *m_bytesRead += 2;
+  if (len != 1)
+    return -1;
+
+  *value = buf[0] | buf[1] << 8;
+  return 0;
+}
+
+unsigned char *load_bitmap_file (const char* filename, guint16 *width, guint16 *height)
+{
+  int bmWidth, bmHeight;
+  short unsigned bmPlanes, bmBitsPixel;
+  typedef struct {
+    unsigned char rgbBlue;
+    unsigned char rgbGreen;
+    unsigned char rgbRed;
+    unsigned char rgbReserved;
+  } RGBQUAD;
+  unsigned char m1,m2;
+  int sizeimage;
+  short unsigned res1,res2;
+  int filesize, pixoff;
+  int bmisize, compression;
+  int xscale, yscale;
+  int colors, impcol;
+  unsigned long m_bytesRead = 0;
+  unsigned char *imagebits = NULL;
+  FILE *fp;
+
+  *width = *height = 0;
+
+  fp = fopen(filename,"rb");
+  if (fp == NULL)
+  {
+       return NULL;
+  }
+
+  size_t rc;
+  rc = fread(&m1, 1, 1, fp);
+  m_bytesRead++;
+  if (rc == -1)
+  {
+      fclose(fp);
+      return NULL;
+  }
+
+  rc = fread(&m2, 1, 1, fp);
+  m_bytesRead++;
+  if ((m1!='B') || (m2!='M'))
+  {
+      fclose(fp);
+      return NULL;
+  }
+
+  if (readLongLE(fp,&m_bytesRead,&filesize)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readShortLE(fp,&m_bytesRead,&res1)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readShortLE(fp,&m_bytesRead,&res2)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readLongLE(fp,&m_bytesRead,&pixoff)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readLongLE(fp,&m_bytesRead,&bmisize)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readLongLE(fp,&m_bytesRead,&bmWidth)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readLongLE(fp,&m_bytesRead,&bmHeight)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readShortLE(fp,&m_bytesRead,&bmPlanes)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readShortLE(fp,&m_bytesRead,&bmBitsPixel)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readLongLE(fp,&m_bytesRead,&compression)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readLongLE(fp,&m_bytesRead,&sizeimage)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readLongLE(fp,&m_bytesRead,&xscale)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readLongLE(fp,&m_bytesRead,&yscale)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readLongLE(fp,&m_bytesRead,&colors)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (readLongLE(fp,&m_bytesRead,&impcol)) {
+       fclose(fp);
+       return NULL;
+  }
+
+  if (colors == 0)
+    colors = 1 << bmBitsPixel;
+
+  RGBQUAD *colormap = NULL;
+  if (bmBitsPixel != 24)
+  {
+       colormap = new RGBQUAD[colors];
+       if (colormap == NULL)
+       {
+         fclose(fp);
+         return NULL;
+       }
+
+       int i;
+       for (i = 0; i < colors; i++)
+       {
+         unsigned char r ,g, b, dummy;
+
+         rc = fread(&b, 1, 1, fp);
+         m_bytesRead++;
+         if (rc!=1)
+         {
+               delete [] colormap;
+               fclose(fp);
+               return NULL;
+         }
+
+         rc = fread(&g, 1, 1, fp); 
+         m_bytesRead++;
+         if (rc!=1)
+         {
+               delete [] colormap;
+               fclose(fp);
+               return NULL;
+         }
+
+         rc = fread(&r, 1, 1, fp); 
+         m_bytesRead++;
+         if (rc != 1)
+         {
+               delete [] colormap;
+               fclose(fp);
+               return NULL;
+         }
+
+         rc = fread(&dummy, 1, 1, fp); 
+         m_bytesRead++;
+         if (rc != 1)
+         {
+               delete [] colormap;
+               fclose(fp);
+               return NULL;
+         }
+
+         colormap[i].rgbRed=r;
+         colormap[i].rgbGreen=g;
+         colormap[i].rgbBlue=b;
+    }
+  }
+
+  if ((long)m_bytesRead > pixoff)
+  {
+       delete [] colormap;
+       fclose(fp);
+       return NULL;
+  }
+
+  while ((long)m_bytesRead < pixoff)
+  {
+       char dummy;
+       fread(&dummy,1,1,fp);
+       m_bytesRead++;
+  }
+
+  int w = bmWidth;
+  int h = bmHeight;
+
+  // set the output params
+  imagebits = (unsigned char *)malloc(w * h * 3);
+  long row_size = w * 3;
+
+  if (imagebits != NULL) 
+  {
+         *width = w;
+         *height = h;
+         unsigned char *outbuf = imagebits;
+         long row = 0;
+         long rowOffset = 0;
+
+         if (compression == 0) // BI_RGB
+    {
+           // read rows in reverse order
+           for (row = bmHeight - 1; row >= 0; row--)
+           {
+                   // which row are we working on?
+                   rowOffset = (long unsigned)row * row_size;                                                
+
+                   if (bmBitsPixel == 24)
+                   {
+                     for (int col=0;col<w;col++)
+                     {
+                           long offset = col * 3;
+                           char pixel[3];
+
+                           if (fread((void *)(pixel),1,3,fp) == 3)
+                           {
+                             // we swap red and blue here
+                             *(outbuf + rowOffset + offset + 0) = pixel[2];  // r
+                             *(outbuf + rowOffset + offset + 1) = pixel[1];  // g
+                             *(outbuf + rowOffset + offset + 2) = pixel[0];  // b
+                           }
+              }
+                     m_bytesRead += row_size;
+
+                     // read DWORD padding
+                     while ((m_bytesRead - pixoff) & 3)
+                     {
+                             char dummy;
+                             if (fread(&dummy,1,1,fp) != 1)
+            {
+                         free(imagebits);
+                         fclose(fp);
+                         return NULL;
+            }
+                             m_bytesRead++;
+          }
+        }
+        else
+        {
+                     // pixels are packed as 1 , 4 or 8 bit vals. need to unpack them
+                     int bit_count = 0;
+                     unsigned long mask = (1 << bmBitsPixel) - 1;
+                     unsigned char inbyte = 0;
+
+                     for (int col = 0; col < w; col++)
+          {
+                       int pix = 0;
+
+                       // if we need another byte
+                       if (bit_count <= 0)
+                             {
+                               bit_count = 8;
+                               if (fread(&inbyte,1,1,fp) != 1)
+                               {
+                                       free(imagebits);
+                                       delete [] colormap;
+                                       fclose(fp);
+                                       return NULL;
+                               }
+                               m_bytesRead++;
+                             }
+
+                             // keep track of where we are in the bytes
+                             bit_count -= bmBitsPixel;
+                             pix = ( inbyte >> bit_count) & mask;
+
+                             // lookup the color from the colormap - stuff it in our buffer
+                             // swap red and blue
+                             *(outbuf + rowOffset + col * 3 + 2) = colormap[pix].rgbBlue;
+                             *(outbuf + rowOffset + col * 3 + 1) = colormap[pix].rgbGreen;
+                             *(outbuf + rowOffset + col * 3 + 0) = colormap[pix].rgbRed;
+          }
+
+                     // read DWORD padding
+                     while ((m_bytesRead - pixoff) & 3)
+          {
+            char dummy;
+            if (fread(&dummy,1,1,fp)!=1)
+            {
+              free(imagebits);
+              if (colormap)
+                delete [] colormap;
+              fclose(fp);
+              return NULL;
+            }
+            m_bytesRead++;
+          }
+        }
+      }
+    }
+         else
+         {
+           int i, x = 0;
+           unsigned char c, c1 = 0, *pp;
+           row = 0;
+           pp = outbuf + (bmHeight - 1) * bmWidth * 3;
+    
+           if (bmBitsPixel == 8)
+           {
+                   while (row < bmHeight)
+                   {
+                     c = getc(fp);
+       
+                     if (c)
+                     {
+                             // encoded mode
+                             c1 = getc(fp);
+                             for (i = 0; i < c; x++, i++)
+                             {
+                               *pp = colormap[c1].rgbRed; pp++;
+                               *pp = colormap[c1].rgbGreen; pp++;
+                               *pp = colormap[c1].rgbBlue; pp++;
+                             }
+                     }
+                     else
+                     {
+                             // c==0x00,  escape codes
+                             c = getc(fp);
+                             if (c == 0x00) // end of line
+                             {
+                               row++;
+                               x = 0;
+                               pp = outbuf + (bmHeight - row - 1) * bmWidth * 3;
+                             }
+                             else if (c == 0x01)
+                               break; // end of pic
+                             else if (c == 0x02) // delta
+                             {
+                               c = getc(fp);
+                               x += c;
+                               c = getc(fp);
+                               row += c;
+                               pp = outbuf + x*3 + (bmHeight - row - 1) * bmWidth * 3;
+                             }
+                             else // absolute mode
+                             {
+                               for (i = 0; i < c; x++, i++)
+                               {
+                                       c1 = getc(fp);
+                                       *pp = colormap[c1].rgbRed; pp++;
+                                       *pp = colormap[c1].rgbGreen; pp++;
+                                       *pp = colormap[c1].rgbBlue; pp++;
+                               }
+        
+                               if (c & 1)
+                                     getc(fp); // odd length run: read an extra pad byte
+                             }
+                     }
+                   }
+           }
+           else if (bmBitsPixel == 4)
+           {
+                   while (row < bmHeight)
+                   {
+                     c = getc(fp);
+      
+                     if (c)
+                     {
+                             // encoded mode
+                             c1 = getc(fp);
+                             for (i = 0; i < c; x++, i++)
+                             {
+                               *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++;
+                               *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++;
+                               *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++;
+                             }
+                     }
+                     else
+                     {
+                             // c==0x00,  escape codes
+                             c = getc(fp);
+        
+                             if (c == 0x00) // end of line
+                             {
+                               row++;
+                               x = 0;
+                               pp = outbuf + (bmHeight - row - 1) * bmWidth * 3;
+                             }
+                             else if (c == 0x01)
+                               break; // end of pic
+                             else if (c == 0x02) // delta
+                             {
+                               c = getc(fp);
+                               x += c;
+                               c = getc(fp);
+                               row += c;
+                               pp = outbuf + x * 3 + (bmHeight - row - 1) * bmWidth * 3;
+                             }
+                             else // absolute mode
+                             {
+                               for (i = 0; i < c; x++, i++)
+                               {
+                                       if ((i&1) == 0)
+                                         c1 = getc(fp);
+                                       *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++;
+                                       *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++;
+                                       *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++;
+                               }
+        
+                               if (((c & 3) == 1) || ((c & 3) == 2))
+                                     getc(fp); // odd length run: read an extra pad byte
+            }
+          }
+                   }
+           }
+         }
+         if (colormap)
+           delete [] colormap;
+    
+         fclose(fp);
+  }
+  return imagebits;
+}
+
+void bmp_to_pixmap (const char* filename, GdkPixmap **pixmap, GdkBitmap **mask)
+{
+  guint16 width, height;
+  unsigned char *buf;
+  GdkWindow *window = gdk_get_default_root_window();
+  GdkColormap *colormap;
+  GdkGC* gc = gdk_gc_new (window);
+  int i, j;
+  bool hasMask = false;
+
+  *pixmap = *mask = NULL;
+  buf = load_bitmap_file (filename, &width, &height);
+  if (!buf)
+    return;
+
+  colormap = gdk_drawable_get_colormap (window);
+  *pixmap = gdk_pixmap_new (window, width, height, -1);
+
+  typedef struct
+  {
+    GdkColor c;
+    unsigned char *p;
+  } PAL;
+
+  for (i = 0; i < height; i++)
+  {
+    for (j = 0; j < width; j++)
+    {
+      unsigned char *p = &buf[(i * width + j) * 3];
+      PAL pe;
+
+      pe.c.red = (gushort)(p[0] * 0xFF);
+      pe.c.green = (gushort)(p[1] * 0xFF);
+      pe.c.blue = (gushort)(p[2] * 0xFF);
+      gdk_colormap_alloc_color(colormap, &pe.c, FALSE, TRUE);
+      gdk_gc_set_foreground(gc, &pe.c);
+      gdk_draw_point(*pixmap, gc, j, i);
+
+      if (p[0] == 0xFF && p[1] == 0x00 && p[2] == 0xFF)
+        hasMask = true;
+    }
+  }
+
+  gdk_gc_unref (gc);
+  *mask = gdk_pixmap_new (window, width, height, 1);
+  gc = gdk_gc_new (*mask);
+  if (hasMask)
+  {
+    for (i = 0; i < height; i++)
+    {
+      for (j = 0; j < width; j++)
+      {
+             GdkColor mask_pattern;
+
+             // pink is transparent
+             if ((buf[(i*width+j)*3] == 0xff) &&
+                     (buf[(i*width+j)*3+1] == 0x00) &&
+                     (buf[(i*width+j)*3+2] == 0xff))
+                     mask_pattern.pixel = 0;
+        else
+                     mask_pattern.pixel = 1;
+
+        gdk_gc_set_foreground (gc, &mask_pattern);
+        // possible Win32 Gtk bug here
+        //gdk_draw_point (*mask, gc, j, i);
+        gdk_draw_line (*mask, gc, j, i, j + 1, i);
+      }
+    }
+  }
+  else
+  {
+    GdkColor mask_pattern;
+    mask_pattern.pixel = 1;
+    gdk_gc_set_foreground (gc, &mask_pattern);
+    gdk_draw_rectangle (*mask, gc, 1, 0, 0, width, height);
+  }
+  gdk_gc_unref(gc);
+  free (buf);
+}
+
+void load_pixmap (const char* filename, GtkWidget* widget, GdkPixmap **gdkpixmap, GdkBitmap **mask)
+{
+  CString str;
+
+  str = g_strBitmapsPath;
+  str += filename;
+
+  bmp_to_pixmap (str.GetBuffer (), gdkpixmap, mask);
+  if (*gdkpixmap == NULL)
+  {
+    printf("gdkpixmap was null\n");
+    char *dummy[] = { "1 1 1 1", "  c None", " " };
+    printf("calling gdk_pixmap_create_from_xpm_d\n");
+    *gdkpixmap = gdk_pixmap_create_from_xpm_d (gdk_get_default_root_window(), mask, NULL, dummy);
+  }
+}
+
+// this is the same as above but used by the plugins
+// GdkPixmap **gdkpixmap, GdkBitmap **mask
+bool WINAPI load_plugin_bitmap (const char* filename, void **gdkpixmap, void **mask)
+{
+  CString str;
+
+  str = g_strGameToolsPath;
+  str += g_strPluginsDir;
+  str += "bitmaps/";
+  str += filename;
+  bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask);
+
+  if (*gdkpixmap == NULL)
+  {
+    // look in the core plugins
+    str = g_strAppPath;
+    str += g_strPluginsDir;
+    str += "bitmaps/";
+    str += filename;
+    bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask);
+
+    if (*gdkpixmap == NULL)
+    {
+      
+      // look in core modules
+      str = g_strAppPath;
+      str += g_strModulesDir;
+      str += "bitmaps/";
+      str += filename;
+      bmp_to_pixmap (str.GetBuffer (), (GdkPixmap **)gdkpixmap, (GdkBitmap **)mask);
+      
+      if (*gdkpixmap == NULL)
+      {
+        char *dummy[] = { "1 1 1 1", "  c None", " " };
+        *gdkpixmap = gdk_pixmap_create_from_xpm_d (gdk_get_default_root_window(), (GdkBitmap **)mask, NULL, dummy);
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+// Load a xpm file and return a pixmap widget.
+GtkWidget* new_pixmap (GtkWidget* widget, char* filename)
+{
+  GdkPixmap *gdkpixmap;
+  GdkBitmap *mask;
+  GtkWidget *pixmap;
+
+  load_pixmap (filename, widget, &gdkpixmap, &mask);
+  pixmap = gtk_pixmap_new (gdkpixmap, mask);
+
+  gdk_drawable_unref (gdkpixmap);
+  gdk_drawable_unref (mask);
+
+  return pixmap;
+} 
+
+// =============================================================================
+// Menu stuff
+
+GtkWidget* menu_separator (GtkWidget *menu)
+{
+  GtkWidget *menu_item = gtk_menu_item_new ();
+  gtk_menu_append (GTK_MENU (menu), menu_item);
+  gtk_widget_set_sensitive (menu_item, FALSE);
+  gtk_widget_show (menu_item);
+  return menu_item;
+}
+
+GtkWidget* menu_tearoff (GtkWidget *menu)
+{
+  GtkWidget *menu_item = gtk_tearoff_menu_item_new ();
+  gtk_menu_append (GTK_MENU (menu), menu_item);
+// gtk_widget_set_sensitive (menu_item, FALSE); -- controls whether menu is detachable
+  gtk_widget_show (menu_item);
+  return menu_item;
+}
+GtkWidget* create_sub_menu_with_mnemonic (GtkWidget *bar, gchar *mnemonic)
+{
+  GtkWidget *item, *sub_menu;
+
+  item = gtk_menu_item_new_with_mnemonic (mnemonic);
+  gtk_widget_show (item);
+  gtk_container_add (GTK_CONTAINER (bar), item);
+
+  sub_menu = gtk_menu_new ();
+  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), sub_menu);
+
+  return sub_menu;
+}
+
+extern void AddMenuItem (GtkWidget* menu, unsigned int id);
+
+GtkWidget* create_menu_item_with_mnemonic (GtkWidget *menu, gchar *mnemonic, GtkSignalFunc func, int id)
+{
+  GtkWidget *item;
+
+  item = gtk_menu_item_new_with_mnemonic (mnemonic);
+
+  gtk_widget_show (item);
+  gtk_container_add (GTK_CONTAINER (menu), item);
+  gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id));
+
+  AddMenuItem (item, id);
+  return item;
+}
+
+GtkWidget* create_check_menu_item_with_mnemonic (GtkWidget *menu, gchar *mnemonic, GtkSignalFunc func, int id, gboolean active)
+{
+  GtkWidget *item;
+
+  item = gtk_check_menu_item_new_with_mnemonic(mnemonic);
+
+  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), active);
+  gtk_widget_show (item);
+  gtk_container_add (GTK_CONTAINER (menu), item);
+  gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id));
+
+  AddMenuItem (item, id);
+  return item;
+}
+
+GtkWidget* create_radio_menu_item_with_mnemonic (GtkWidget *menu, GtkWidget *last, gchar *mnemonic, GtkSignalFunc func, int id, gboolean state)
+{
+  GtkWidget *item;
+  GSList *group = (GSList*)NULL;
+
+  if (last != NULL)
+    group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (last));
+  item = gtk_radio_menu_item_new_with_mnemonic (group, mnemonic);
+  gtk_check_menu_item_set_state (GTK_CHECK_MENU_ITEM (item), state);
+
+  gtk_widget_show (item);
+  gtk_container_add (GTK_CONTAINER (menu), item);
+  gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (func), GINT_TO_POINTER (id));
+
+  AddMenuItem (item, id);
+  return item;
+}
+
+GtkWidget* create_menu_in_menu_with_mnemonic (GtkWidget *menu, const gchar *mnemonic)
+{
+  GtkWidget *item, *submenu;
+
+  item = gtk_menu_item_new_with_mnemonic(mnemonic);
+  gtk_widget_show (item);
+  gtk_container_add (GTK_CONTAINER (menu), item);
+
+  submenu = gtk_menu_new ();
+  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
+
+  return submenu;
+}
+
+// =============================================================================
+// Message Boxes
+
+void dialog_button_callback( GtkWidget *widget, gpointer data ) {
+  GtkWidget *parent;
+  int *loop, *ret;
+
+  parent = gtk_widget_get_toplevel( widget );
+  loop = (int*)g_object_get_data( G_OBJECT( parent ), "loop" );
+  ret = (int*)g_object_get_data( G_OBJECT( parent ), "ret" );
+
+  *loop = 0;
+  *ret = (int)data;
+}
+
+gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data)
+{
+  int *loop;
+
+  gtk_widget_hide (widget);
+  loop = (int*)g_object_get_data (G_OBJECT (widget), "loop");
+  *loop = 0;
+
+  return TRUE;
+}
+
+gint dialog_url_callback (GtkWidget *widget, GdkEvent* event, gpointer data)
+{
+  OpenURL((const char *)g_object_get_data (G_OBJECT (widget), "URL"));
+
+  return TRUE;
+}
+
+int WINAPI gtk_MessageBox (void *parent, const char* lpText, const char* lpCaption, guint32 uType, const char* URL)
+{
+  GtkWidget *window, *w, *vbox, *hbox;
+  GtkAccelGroup *accel;
+  int mode = (uType & MB_TYPEMASK), ret, loop = 1;
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                      GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                      GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);
+  gtk_window_set_title (GTK_WINDOW (window), lpCaption);
+  gtk_container_border_width (GTK_CONTAINER (window), 10);
+  g_object_set_data (G_OBJECT (window), "loop", &loop);
+  g_object_set_data (G_OBJECT (window), "ret", &ret);
+  gtk_widget_realize (window);
+
+  gtk_window_set_policy(GTK_WINDOW (window),FALSE,FALSE,TRUE);
+
+  if (parent != NULL)
+    gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent));
+
+  accel = gtk_accel_group_new ();
+  gtk_window_add_accel_group (GTK_WINDOW (window), accel);
+
+  vbox = gtk_vbox_new (FALSE, 10);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+  gtk_widget_show (vbox);
+
+  w = gtk_label_new (lpText);
+  gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);
+  gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT);
+  gtk_widget_show (w);
+
+  w = gtk_hseparator_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2);
+  gtk_widget_show (w);
+
+  hbox = gtk_hbox_new (FALSE, 10);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2);
+  gtk_widget_show (hbox);
+  if (mode == MB_OK)
+  {
+    w = gtk_button_new_with_label ("Ok");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));
+    gtk_widget_add_accelerator (w, "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
+    gtk_widget_add_accelerator (w, "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
+    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default (w);
+    gtk_widget_show (w);
+    ret = IDOK;
+  }
+  else if (mode ==  MB_OKCANCEL)
+  {
+    w = gtk_button_new_with_label ("Ok");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));
+    gtk_widget_add_accelerator (w, "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
+    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default (w);
+    gtk_widget_show (w);
+
+    w = gtk_button_new_with_label ("Cancel");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));
+    gtk_widget_add_accelerator (w, "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
+    gtk_widget_show (w);
+    ret = IDCANCEL;
+  }
+  else if (mode == MB_YESNOCANCEL)
+  {
+    w = gtk_button_new_with_label ("Yes");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES));
+    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default (w);
+    gtk_widget_show (w);
+    w = gtk_button_new_with_label ("No");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO));
+    gtk_widget_show (w);
+    w = gtk_button_new_with_label ("Cancel");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));
+    gtk_widget_show (w);
+    ret = IDCANCEL;
+  }
+  else /* if (mode == MB_YESNO) */
+  {
+    w = gtk_button_new_with_label ("Yes");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES));
+    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default (w);
+    gtk_widget_show (w);
+    w = gtk_button_new_with_label ("No");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO));
+    gtk_widget_show (w);
+    ret = IDNO;
+  }
+
+  if (URL)
+  {
+    w = gtk_button_new_with_label ("Go to URL");
+    gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT (w), "clicked",
+                        GTK_SIGNAL_FUNC (dialog_url_callback), NULL);
+    g_object_set_data (G_OBJECT (w), "URL", (void *)URL);
+    GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default (w);
+    gtk_widget_show (w);
+  }
+
+
+  gtk_widget_show (window);
+  gtk_grab_add (window);
+
+  while (loop)
+    gtk_main_iteration ();
+
+  gtk_grab_remove (window);
+  gtk_widget_destroy (window);
+
+  return ret;
+}
+
+// =============================================================================
+// File dialog
+
+// fenris #3078 WHENHELLISFROZENOVER
+
+//#define FILEDLG_DBG
+
+static void file_sel_callback (GtkWidget *widget, gpointer data)
+{
+  GtkWidget *parent;
+  int *loop;
+  bool *success;
+
+  parent = gtk_widget_get_toplevel (widget);
+  loop = (int*)g_object_get_data (G_OBJECT (parent), "loop");
+  success = (bool*)g_object_get_data (G_OBJECT (parent), "success");
+  
+  if ((int)data == IDOK)
+    *success = true;
+
+#ifdef FILEDLG_DBG
+  else
+    Sys_Printf("file_sel_callback != IDOK\n");
+#endif
+  
+  *loop = 0;
+}
+
+#ifdef _WIN32
+#include <commdlg.h>
+static OPENFILENAME ofn;       /* common dialog box structure   */ 
+static char szDirName[MAX_PATH];    /* directory string              */ 
+static char szFile[MAX_PATH];       /* filename string               */ 
+static char szFileTitle[MAX_PATH];  /* file title string             */ 
+static int i, cbString;        /* integer count variables       */ 
+static HANDLE hf;              /* file handle                   */ 
+#else
+static char szFile[QER_MAX_NAMELEN];
+#endif
+
+#define FILEDLG_CUSTOM_FILTER_LENGTH 64
+// to be used with the advanced file selector
+
+class CFileType : public IFileTypeList
+{
+  struct filetype_copy_t
+  {
+    void operator=(const filetype_t& other)
+    {
+      m_name = other.name;
+      m_pattern = other.pattern;
+    }
+    string_t m_name;
+    string_t m_pattern;
+  };
+public:
+  CFileType()
+  {
+    m_nTypes = 0;
+    m_pTypes = NULL;
+    m_strWin32Filters = NULL;
+    m_pstrGTKMasks = NULL;
+  }
+
+  virtual ~CFileType()
+  {
+    delete[] m_pTypes;
+    DestroyWin32Filters();
+    DestroyGTKMasks();
+  }
+
+  void addType(filetype_t type)
+  {
+    filetype_copy_t* newTypes = new filetype_copy_t [m_nTypes+1];
+    if(m_nTypes > 0)
+    {
+      for(int i=0; i<m_nTypes; i++)
+        newTypes[i] = m_pTypes[i];
+      delete[] m_pTypes;
+    }
+    m_pTypes = newTypes;
+    m_pTypes[m_nTypes] = type;
+    m_nTypes++;
+    ConstructGTKMasks();
+    ConstructWin32Filters();
+  }
+  filetype_t GetTypeForWin32Filter(const char *filter) const
+  {
+    for(int i=0; i<m_nTypes; i++)
+      if(strcmp(m_pTypes[i].m_pattern.c_str(), filter)==0)
+        return filetype_t(m_pTypes[i].m_name.c_str(), m_pTypes[i].m_pattern.c_str());
+    return filetype_t();
+  }
+
+  filetype_t GetTypeForGTKMask(const char *mask) const
+  {
+    for(int i=0; i<m_nTypes; i++)
+      if(strcmp(m_pstrGTKMasks[i],mask)==0)
+        return filetype_t(m_pTypes[i].m_name.c_str(), m_pTypes[i].m_pattern.c_str());
+    return filetype_t();
+  }
+
+  char *m_strWin32Filters;
+  char **m_pstrGTKMasks;
+private:
+  int m_nTypes;
+  filetype_copy_t *m_pTypes;
+
+  void DestroyWin32Filters()
+  {
+    delete[] m_strWin32Filters;
+  }
+
+  void ConstructWin32Filters()
+  {
+    const char *r;
+    char *w;
+    int i;
+    int len = 0;
+    DestroyWin32Filters();
+    for(i=0; i<m_nTypes; i++)
+      len = len + strlen(m_pTypes[i].m_name.c_str()) + strlen(m_pTypes[i].m_pattern.c_str())*2 + 5;
+    m_strWin32Filters = new char[len+1]; // length + null char
+    for(i=0, w = m_strWin32Filters; i<m_nTypes; i++)
+    {
+      for(r = m_pTypes[i].m_name.c_str(); *r!='\0'; r++, w++)
+        *w = *r;
+      *w++ = ' ';
+      *w++ = '(';
+      for(r = m_pTypes[i].m_pattern.c_str(); *r!='\0'; r++, w++)
+        *w = *r;
+      *w++ = ')';
+      *w++ = '\0';
+      for(r = m_pTypes[i].m_pattern.c_str(); *r!='\0'; r++, w++)
+        *w = (*r == ',') ? ';' : *r;
+      *w++ = '\0';
+    }
+    m_strWin32Filters[len] = '\0';
+  }
+
+  void DestroyGTKMasks()
+  {
+    if(m_pstrGTKMasks != NULL)
+      for(char **p = m_pstrGTKMasks; *p != NULL; p++)
+        delete[] *p;
+    delete[] m_pstrGTKMasks;
+  }
+  
+  void ConstructGTKMasks()
+  {
+    const char *r;
+    char *w;
+    int i;
+    int len = 0;
+    DestroyGTKMasks();
+    m_pstrGTKMasks = new char*[m_nTypes+1];
+    for(i=0; i<m_nTypes; i++)
+    {
+      len = strlen(m_pTypes[i].m_name.c_str()) + strlen(m_pTypes[i].m_pattern.c_str()) + 3;
+      m_pstrGTKMasks[i] = new char[len+1]; // length + null char
+      w = m_pstrGTKMasks[i];
+      for(r = m_pTypes[i].m_name.c_str(); *r!='\0'; r++, w++)
+        *w = *r;
+      *w++ = ' ';
+      *w++ = '<';
+      for(r = m_pTypes[i].m_pattern.c_str(); *r!='\0'; r++, w++)
+        *w = *r;
+      *w++ = '>';
+      *w++ = '\0';
+    }
+    m_pstrGTKMasks[m_nTypes] = NULL;
+  }
+
+};
+
+const char* file_dialog (void *parent, gboolean open, const char* title, const char* path, const char* pattern)
+{
+  // Gtk dialog
+  GtkWidget* file_sel;
+  int loop = 1;
+  char *new_path = NULL;
+
+  const char* r;
+  char* w;
+  filetype_t type;
+  CFileType typelist;
+  if(pattern != NULL)
+    GetFileTypeRegistry()->getTypeList(pattern, &typelist);
+
+#ifdef FILEDLG_DBG
+  Sys_Printf("file_dialog: open = %d title = %s path = %s\n", open, title, path);
+  if (pattern)
+  {
+    Sys_Printf("Patterns:\n");
+    char** p = typelist.m_pstrGTKMasks;
+    while(*p!=NULL)
+      Sys_Printf("%s\n", *p++);
+  }
+  else
+    Sys_Printf("no patterns\n");
+#endif
+
+#ifdef _WIN32
+  // win32 dialog stores the selected "save as type" extension in the second null-terminated string
+  char customfilter[FILEDLG_CUSTOM_FILTER_LENGTH];
+
+  if (g_PrefsDlg.m_bNativeGUI)
+  {
+#ifdef FILEDLG_DBG
+    Sys_Printf("Doing win32 file dialog...");
+#endif
+    // do that the native way
+    /* Place the terminating null character in the szFile. */  
+    szFile[0] = '\0';
+    customfilter[0] = customfilter[1] = customfilter[2] = '\0';
+    
+    /* Set the members of the OPENFILENAME structure. */     
+    ofn.lStructSize = sizeof(OPENFILENAME); 
+    ofn.hwndOwner = (HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window);
+    if (pattern)
+    {
+      ofn.nFilterIndex = 0;
+      ofn.lpstrFilter = typelist.m_strWin32Filters;
+    }
+    else ofn.nFilterIndex = 1;
+    ofn.lpstrCustomFilter = customfilter;
+    ofn.nMaxCustFilter = sizeof(customfilter);
+    ofn.lpstrFile = szFile;
+    ofn.nMaxFile = sizeof(szFile); 
+    ofn.lpstrFileTitle = NULL; // we don't need to get the name of the file
+    if(path)
+    {
+      // szDirName: Radiant uses unix convention for paths internally
+      //   Win32 (of course) and Gtk (who would have thought) expect the '\\' convention
+      // copy path, replacing dir separators as appropriate
+      for(r=path, w=szDirName; *r!='\0'; r++)
+        *w++ = (*r=='/') ? '\\' : *r;
+      // terminate string
+      *w = '\0';
+      ofn.lpstrInitialDir = szDirName;
+    }
+    else ofn.lpstrInitialDir = NULL;
+    ofn.lpstrTitle = title;
+    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; 
+
+    /* Display the Open dialog box. */
+    // it's open or close depending on 'open' parameter
+    if (open)
+    {
+      if (!GetOpenFileName(&ofn))
+        return NULL;   // canceled
+    }
+    else
+    {
+      if (!GetSaveFileName(&ofn))
+        return NULL;   // canceled
+    }
+
+    if(pattern != NULL)
+      type = typelist.GetTypeForWin32Filter(customfilter+1);
+    
+#ifdef FILEDLG_DBG
+    Sys_Printf("Done.\n");
+#endif
+  }
+  else
+  {
+#endif
+    // do that the Gtk way
+    if (title == NULL)
+      title = open ? "Open File" : "Save File";
+    
+#ifdef FILEDLG_DBG
+    Sys_Printf("Doing Gtk file dialog:\nBuilding new_path..");
+#endif
+    // we expect an actual path below, if the path is NULL we might crash
+    if (!path || path[0] == '\0')
+    {
+#ifdef _WIN32
+      path = "C:\\";
+#elif defined (__linux__) || defined (__APPLE__)
+      path = "/";
+#else
+      path = "/";
+#endif
+    }
+
+    // alloc new path with extra char for dir separator
+    new_path = new char[strlen(path)+1+1];
+    // copy path, replacing dir separators as appropriate
+    for(r=path, w=new_path; *r!='\0'; r++)
+      *w++ = (*r=='/') ? G_DIR_SEPARATOR : *r;
+    // add dir separator to end of path if required
+    if(*(w-1) != G_DIR_SEPARATOR) *w++ = G_DIR_SEPARATOR;
+    // terminate string
+    *w = '\0';
+
+#ifdef FILEDLG_DBG
+    Sys_Printf("Done.\n");
+    Sys_Printf("Calling gtk_file_selection_new with title: %s...", title);
+#endif
+
+    file_sel = gtk_file_selection_new (title);
+
+#ifdef FILEDLG_DBG
+    Sys_Printf("Done.\n");
+    Sys_Printf("Set the masks...");
+#endif
+
+#if 0 //!\todo Add masks to GtkFileSelection in gtk-2.0
+    // set the masks
+    if (pattern)
+    {
+      gtk_file_selection_clear_masks (GTK_FILE_SELECTION (file_sel));
+      gtk_file_selection_set_masks (GTK_FILE_SELECTION (file_sel), const_cast<const char**>(typelist.m_pstrGTKMasks));
+    }
+#endif
+
+#ifdef FILEDLG_DBG
+    Sys_Printf("Done.\n");
+#endif
+
+    gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked",
+      GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK));
+    gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked",
+      GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL));
+    gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event",
+      GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);
+    gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel));
+    
+    if (parent != NULL)
+      gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent));
+    
+#ifdef FILEDLG_DBG
+    Sys_Printf("set_data...");
+#endif
+    bool success = false;
+    g_object_set_data (G_OBJECT (file_sel), "loop", &loop);
+    g_object_set_data (G_OBJECT (file_sel), "success", &success);
+#ifdef FILEDLG_DBG
+    Sys_Printf("Done.\n");
+#endif
+    
+    if (!open)
+    {
+#ifdef FILEDLG_DBG
+      Sys_Printf("set_data \"overwrite\" ...");
+#endif
+      g_object_set_data (G_OBJECT (file_sel), "overwrite", GINT_TO_POINTER (1));
+#ifdef FILEDLG_DBG
+      Sys_Printf("Done.\n");
+#endif
+    }
+    
+    if (new_path != NULL)
+    {
+#ifdef FILEDLG_DBG
+      Sys_Printf("gtk_file_selection_set_filename... %p", file_sel); 
+#endif
+      gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), new_path);
+      delete[] new_path;
+#ifdef FILEDLG_DBG
+      Sys_Printf("Done.\n");
+#endif
+    }
+
+    gtk_grab_add (file_sel);
+#ifdef FILEDLG_DBG
+    Sys_Printf("gtk_widget_show... %p", file_sel); 
+#endif
+    gtk_widget_show (file_sel);
+#ifdef FILEDLG_DBG
+    Sys_Printf("Done.\n"); 
+#endif
+
+#ifdef FILEDLG_DBG
+    Sys_Printf("gtk_main_iteration..."); 
+#endif
+    while (loop)
+      gtk_main_iteration ();
+    if(success)
+    {
+#if 0 //!\todo Add masks to GtkFileSelection in gtk2
+      if(pattern!=NULL)
+        type = typelist.GetTypeForGTKMask(GTK_FILE_SELECTION (file_sel)->mask);
+#endif
+      strcpy(szFile, gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel)));
+    }
+#ifdef FILEDLG_DBG
+    Sys_Printf("Done.\n");
+#endif
+    
+    gtk_grab_remove (file_sel);
+    gtk_widget_destroy (file_sel);
+#ifdef _WIN32
+  }
+#endif
+
+  // don't return an empty filename
+  if(szFile[0] == '\0') return NULL;
+
+  // convert back to unix format
+  for(w=szFile; *w!='\0'; w++)
+    if(*w=='\\')
+      *w = '/';
+
+#if defined(WIN32)
+  if (g_PrefsDlg.m_bNativeGUI) // filetype mask not supported in gtk dialog yet
+  {
+    // when saving, force an extension depending on filetype
+    /* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */
+    if(!open && pattern != NULL)
+    {
+      // last ext separator
+      w = strrchr(szFile, '.');
+      // no extension
+      w = (w!=NULL) ? w : szFile+strlen(szFile);
+      strcpy(w, type.pattern+1);
+    }
+  }
+#endif
+
+  // prompt to overwrite existing files
+  if (!open)
+    if (access (szFile, R_OK) == 0)
+      if (gtk_MessageBox (parent, "File already exists.\nOverwrite?", "GtkRadiant", MB_YESNO) == IDNO)
+        return NULL;
+
+#ifdef FILEDLG_DBG
+  // ... let's use a static filename
+  Sys_Printf("filename: %p\n", szFile);
+#endif
+
+  return szFile;
+}
+
+char* WINAPI dir_dialog (void *parent, const char* title, const char* path)
+{
+  GtkWidget* file_sel;
+  char* filename = (char*)NULL;
+  int loop = 1;
+  bool success = false;
+
+  file_sel = gtk_file_selection_new (title);
+  gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked",
+                      GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK));
+  gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked",
+                      GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL));
+  gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event",
+                      GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);
+  gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel));
+
+  if (parent != NULL)
+    gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent));
+
+  gtk_widget_hide (GTK_FILE_SELECTION (file_sel)->file_list->parent);
+
+  g_object_set_data (G_OBJECT (file_sel), "loop", &loop);
+  g_object_set_data (G_OBJECT (file_sel), "success", &success);
+
+  if (path != NULL)
+    gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), path);
+
+  gtk_grab_add (file_sel);
+  gtk_widget_show (file_sel);
+
+  while (loop)
+    gtk_main_iteration ();
+
+  filename = g_strdup(gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel)));
+
+  gtk_grab_remove (file_sel);
+  gtk_widget_destroy (file_sel);
+
+  return filename;
+}
+
+bool WINAPI color_dialog (void *parent, float *color, const char* title)
+{
+  GtkWidget* dlg;
+  double clr[3];
+  int loop = 1, ret = IDCANCEL;
+
+  clr[0] = color[0];
+  clr[1] = color[1];
+  clr[2] = color[2];
+
+  dlg = gtk_color_selection_dialog_new (title);
+  gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr);
+  gtk_signal_connect (GTK_OBJECT (dlg), "delete_event",
+                      GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);
+  gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
+                      GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);
+  gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked",
+                     GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK));
+  gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked",
+                     GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL));
+  g_object_set_data (G_OBJECT (dlg), "loop", &loop);
+  g_object_set_data (G_OBJECT (dlg), "ret", &ret);
+
+  if (parent != NULL)
+    gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (parent));
+
+  gtk_widget_show (dlg);
+  gtk_grab_add (dlg);
+
+  while (loop)
+    gtk_main_iteration ();
+
+  GdkColor gdkcolor;
+  gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), &gdkcolor);
+  clr[0] = gdkcolor.red / 65535.0;
+  clr[1] = gdkcolor.green / 65535.0;
+  clr[2] = gdkcolor.blue / 65535.0;
+
+  gtk_grab_remove (dlg);
+  gtk_widget_destroy (dlg);
+
+  if (ret == IDOK)
+  {
+    color[0] = (float)clr[0];
+    color[1] = (float)clr[1];
+    color[2] = (float)clr[2];
+
+    return true;
+  }
+
+  return false;
+}
+
+void OpenURL(const char *url)
+{
+  // let's put a little comment
+  Sys_Printf("OpenURL: %s\n", url);
+#ifdef __linux__
+  // \todo FIXME: the way we open URLs on *nix should be improved. A script is good (see how I do on RTCW)
+  char command[2*PATH_MAX];
+  snprintf( command, sizeof(command), "%s/openurl.sh \"%s\" &", g_strAppPath.GetBuffer(), url );
+  if (system (command) != 0)
+    gtk_MessageBox (g_pParentWnd->m_pWidget, "Failed to launch Netscape!");
+#endif
+#ifdef __APPLE__
+  char command[2*PATH_MAX];
+  snprintf (command, sizeof(command),
+            "open \"%s\" &", url, url);
+  if (system (command) != 0)
+    gtk_MessageBox (g_pParentWnd->m_pWidget, "Unable to launch browser!");
+#endif
+#ifdef _WIN32
+  ShellExecute( (HWND)GDK_WINDOW_HWND (g_pParentWnd->m_pWidget->window), "open", url, NULL, NULL, SW_SHOW );
+#endif
+}
+
+void CheckMenuSplitting (GtkWidget *&menu)
+{
+  GtkWidget *item,*menu2;
+
+  GtkRequisition requisition;
+  gint screen_height;
+
+  gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
+  screen_height = gdk_screen_height ();
+
+  if ((screen_height - requisition.height) < 20)
+  {
+    menu2 = gtk_menu_new ();
+
+    // move the last 2 items to a submenu (3 because of win32)
+    for (int i = 0; i < 3; i++)
+    {
+      item = GTK_WIDGET (g_list_last (gtk_container_children (GTK_CONTAINER (menu)))->data);
+      gtk_widget_ref (item);
+      gtk_container_remove (GTK_CONTAINER (menu), item);
+      gtk_menu_append (GTK_MENU (menu2), item);
+      gtk_widget_unref (item);
+    }
+
+    item = gtk_menu_item_new_with_label ("--------");
+    gtk_widget_show (item);
+    gtk_container_add (GTK_CONTAINER (menu), item);
+    gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu2);
+    menu = menu2;
+  }
+}