// @(#)root/win32gdk:$Id$
// Author: Rene Brun, Olivier Couet, Fons Rademakers, Valeri Onuchin, Bertrand Bellenot 27/11/01

/*************************************************************************
 * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGWin32                                                              //
//                                                                      //
// This class is the basic interface to the Win32 graphics system.      //
// It is  an implementation of the abstract TVirtualX class.            //
//                                                                      //
// This code was initially developed in the context of HIGZ and PAW     //
// by Olivier Couet (package X11INT).                                   //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGWin32.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <process.h>
#include <wchar.h>
#include "gdk/gdkkeysyms.h"
#include "xatom.h"
#include <winuser.h>

#include "TROOT.h"
#include "TApplication.h"
#include "TColor.h"
#include "TPoint.h"
#include "TMath.h"
#include "TStorage.h"
#include "TStyle.h"
#include "TSystem.h"
#include "TGFrame.h"
#include "TError.h"
#include "TException.h"
#include "TClassTable.h"
#include "KeySymbols.h"
#include "TWinNTSystem.h"
#include "TGWin32VirtualXProxy.h"
#include "TGWin32InterpreterProxy.h"
#include "TWin32SplashThread.h"
#include "TString.h"
#include "TObjString.h"
#include "TObjArray.h"
#include "TExMap.h"
#include "TEnv.h"
#include "RStipples.h"
#include "TEnv.h"

// DND protocol version
#define XDND_PROTOCOL_VERSION   5
#ifndef IDC_HAND
#define IDC_HAND  MAKEINTRESOURCE(32649)
#endif

extern "C" {
void gdk_win32_draw_rectangle (GdkDrawable    *drawable,
				      GdkGC          *gc,
				      gint            filled,
				      gint            x,
				      gint            y,
				      gint            width,
				      gint            height);
void gdk_win32_draw_arc       (GdkDrawable    *drawable,
				      GdkGC          *gc,
				      gint            filled,
				      gint            x,
				      gint            y,
				      gint            width,
				      gint            height,
				      gint            angle1,
				      gint            angle2);
void gdk_win32_draw_polygon   (GdkDrawable    *drawable,
				      GdkGC          *gc,
				      gint            filled,
				      GdkPoint       *points,
				      gint            npoints);
void gdk_win32_draw_text      (GdkDrawable    *drawable,
				      GdkFont        *font,
				      GdkGC          *gc,
				      gint            x,
				      gint            y,
				      const gchar    *text,
				      gint            text_length);
void gdk_win32_draw_points    (GdkDrawable    *drawable,
				      GdkGC          *gc,
				      GdkPoint       *points,
				      gint            npoints);
void gdk_win32_draw_segments  (GdkDrawable    *drawable,
				      GdkGC          *gc,
				      GdkSegment     *segs,
				      gint            nsegs);
void gdk_win32_draw_lines     (GdkDrawable    *drawable,
				      GdkGC          *gc,
				      GdkPoint       *points,
				      gint            npoints);

};

//////////// internal classes & structures (very private) ////////////////

struct XWindow_t {
   Int_t    open;                 // 1 if the window is open, 0 if not
   Int_t    double_buffer;        // 1 if the double buffer is on, 0 if not
   Int_t    ispixmap;             // 1 if pixmap, 0 if not
   GdkDrawable *drawing;          // drawing area, equal to window or buffer
   GdkDrawable *window;           // win32 window
   GdkDrawable *buffer;           // pixmap used for double buffer
   UInt_t   width;                // width of the window
   UInt_t   height;               // height of the window
   Int_t    clip;                 // 1 if the clipping is on
   Int_t    xclip;                // x coordinate of the clipping rectangle
   Int_t    yclip;                // y coordinate of the clipping rectangle
   UInt_t   wclip;                // width of the clipping rectangle
   UInt_t   hclip;                // height of the clipping rectangle
   ULong_t *new_colors;           // new image colors (after processing)
   Int_t    ncolors;              // number of different colors
};


/////////////////////////////////// globals //////////////////////////////////
int gdk_debug_level;

namespace {
/////////////////////////////////// globals //////////////////////////////////

GdkAtom gClipboardAtom = GDK_NONE;
static XWindow_t *gCws;         // gCws: pointer to the current window
static XWindow_t *gTws;         // gTws: temporary pointer

//
// gColors[0]           : background also used for b/w screen
// gColors[1]           : foreground also used for b/w screen
// gColors[2..kMAXCOL-1]: colors which can be set by SetColor
//
const Int_t kBIGGEST_RGB_VALUE = 65535;
//const Int_t kMAXCOL = 1000;
//static struct {
//   Int_t defined;
//   GdkColor color;
//} gColors[kMAXCOL];

//
// Primitives Graphic Contexts global for all windows
//
const int kMAXGC = 7;
static GdkGC *gGClist[kMAXGC];
static GdkGC *gGCline;          // = gGClist[0];  // PolyLines
static GdkGC *gGCmark;          // = gGClist[1];  // PolyMarker
static GdkGC *gGCfill;          // = gGClist[2];  // Fill areas
static GdkGC *gGCtext;          // = gGClist[3];  // Text
static GdkGC *gGCinvt;          // = gGClist[4];  // Inverse text
static GdkGC *gGCdash;          // = gGClist[5];  // Dashed lines
static GdkGC *gGCpxmp;          // = gGClist[6];  // Pixmap management

static GdkGC *gGCecho;          // Input echo

static Int_t gFillHollow;       // Flag if fill style is hollow
static GdkPixmap *gFillPattern; // Fill pattern

//
// Text management
//
static char *gTextFont = "arial.ttf";      // Current font

//
// Markers
//
const Int_t kMAXMK = 100;
static struct {
   int type;
   int n;
   GdkPoint xy[kMAXMK];
} gMarker;                      // Point list to draw marker

//
// Keep style values for line GdkGC
//
static int  gLineStyle = GDK_LINE_SOLID;
static int  gCapStyle  = GDK_CAP_BUTT;
static int  gJoinStyle = GDK_JOIN_MITER;
static char gDashList[10];
static int  gDashLength = 0;
static int  gDashOffset = 0;
static int  gDashSize   = 0;

//
// Event masks
//
static ULong_t gMouseMask =
    GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK
    | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK
    | GDK_KEY_RELEASE_MASK;
static ULong_t gKeybdMask =
    GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK | GDK_ENTER_NOTIFY_MASK |
    GDK_LEAVE_NOTIFY_MASK;

//
// Data to create an invisible cursor
//
const char null_cursor_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static GdkCursor *gNullCursor;

static bool gdk_initialized = false;

//---- MWM Hints stuff

struct MWMHintsProperty_t {
   Handle_t fFlags;
   Handle_t fFunctions;
   Handle_t fDecorations;
   Int_t fInputMode;
};

//---- hints

const ULong_t kMWMHintsFunctions = BIT(0);
const ULong_t kMWMHintsDecorations = BIT(1);
const ULong_t kMWMHintsInputMode = BIT(2);

const Int_t kPropMotifWMHintsElements = 4;
const Int_t kPropMWMHintElements = kPropMotifWMHintsElements;


//---- Key symbol mapping

struct KeySymbolMap_t {
   KeySym fXKeySym;
   EKeySym fKeySym;
};

static char *keyCodeToString[] = {
   "",                          /* 0x000 */
   "",                          /* 0x001, VK_LBUTTON */
   "",                          /* 0x002, VK_RBUTTON */
   "",                          /* 0x003, VK_CANCEL */
   "",                          /* 0x004, VK_MBUTTON */
   "",                          /* 0x005 */
   "",                          /* 0x006 */
   "",                          /* 0x007 */
   "\015",                      /* 0x008, VK_BACK */
   "\t",                        /* 0x009, VK_TAB */
   "",                          /* 0x00A */
   "",                          /* 0x00B */
   "",                          /* 0x00C, VK_CLEAR */
   "\r",                        /* 0x00D, VK_RETURN */
   "",                          /* 0x00E */
   "",                          /* 0x00F */
   "",                          /* 0x010, VK_SHIFT */
   "",                          /* 0x011, VK_CONTROL */
   "",                          /* 0x012, VK_MENU */
   "",                          /* 0x013, VK_PAUSE */
   "",                          /* 0x014, VK_CAPITAL */
   "",                          /* 0x015, VK_KANA */
   "",                          /* 0x016 */
   "",                          /* 0x017 */
   "",                          /* 0x018 */
   "",                          /* 0x019, VK_KANJI */
   "",                          /* 0x01A */
   "",                          /* 0x01B, VK_ESCAPE */
   "",                          /* 0x01C, VK_CONVERT */
   "",                          /* 0x01D, VK_NONCONVERT */
   "",                          /* 0x01E */
   "",                          /* 0x01F */
   " ",                         /* 0x020, VK_SPACE */
   "",                          /* 0x021, VK_PRIOR */
   "",                          /* 0x022, VK_NEXT */
   "",                          /* 0x023, VK_END */
   "",                          /* 0x024, VK_HOME */
   "",                          /* 0x025, VK_LEFT */
   "",                          /* 0x026, VK_UP */
   "",                          /* 0x027, VK_RIGHT */
   "",                          /* 0x028, VK_DOWN */
   "",                          /* 0x029, VK_SELECT */
   "",                          /* 0x02A, VK_PRINT */
   "",                          /* 0x02B, VK_EXECUTE */
   "",                          /* 0x02C, VK_SNAPSHOT */
   "",                          /* 0x02D, VK_INSERT */
   "\037",                      /* 0x02E, VK_DELETE */
   "",                          /* 0x02F, VK_HELP */
};

//---- Mapping table of all non-trivial mappings (the ASCII keys map
//---- one to one so are not included)

static KeySymbolMap_t gKeyMap[] = {
   {GDK_Escape, kKey_Escape},
   {GDK_Tab, kKey_Tab},
#ifndef GDK_ISO_Left_Tab
   {0xFE20, kKey_Backtab},
#else
   {GDK_ISO_Left_Tab, kKey_Backtab},
#endif
   {GDK_BackSpace, kKey_Backspace},
   {GDK_Return, kKey_Return},
   {GDK_Insert, kKey_Insert},
   {GDK_Delete, kKey_Delete},
   {GDK_Clear, kKey_Delete},
   {GDK_Pause, kKey_Pause},
   {GDK_Print, kKey_Print},
   {0x1005FF60, kKey_SysReq},   // hardcoded Sun SysReq
   {0x1007ff00, kKey_SysReq},   // hardcoded X386 SysReq
   {GDK_Home, kKey_Home},       // cursor movement
   {GDK_End, kKey_End},
   {GDK_Left, kKey_Left},
   {GDK_Up, kKey_Up},
   {GDK_Right, kKey_Right},
   {GDK_Down, kKey_Down},
   {GDK_Prior, kKey_Prior},
   {GDK_Next, kKey_Next},
   {GDK_Shift_L, kKey_Shift},   // modifiers
   {GDK_Shift_R, kKey_Shift},
   {GDK_Shift_Lock, kKey_Shift},
   {GDK_Control_L, kKey_Control},
   {GDK_Control_R, kKey_Control},
   {GDK_Meta_L, kKey_Meta},
   {GDK_Meta_R, kKey_Meta},
   {GDK_Alt_L, kKey_Alt},
   {GDK_Alt_R, kKey_Alt},
   {GDK_Caps_Lock, kKey_CapsLock},
   {GDK_Num_Lock, kKey_NumLock},
   {GDK_Scroll_Lock, kKey_ScrollLock},
   {GDK_KP_Space, kKey_Space},  // numeric keypad
   {GDK_KP_Tab, kKey_Tab},
   {GDK_KP_Enter, kKey_Enter},
   {GDK_KP_Equal, kKey_Equal},
   {GDK_KP_Multiply, kKey_Asterisk},
   {GDK_KP_Add, kKey_Plus},
   {GDK_KP_Separator, kKey_Comma},
   {GDK_KP_Subtract, kKey_Minus},
   {GDK_KP_Decimal, kKey_Period},
   {GDK_KP_Divide, kKey_Slash},
   {0, (EKeySym) 0}
};


/////////////////////static auxilary functions /////////////////////////////////
//______________________________________________________________________________
static Int_t _lookup_string(Event_t * event, char *buf, Int_t buflen)
{
   int i;
   int n = event->fUser[1];
   if (n > 0) {
      for (i = 0; i < n; i++) {
         buf[i] = event->fUser[2 + i];
      }
      buf[n] = 0;
   } else {
      buf[0] = 0;
   }
   if (event->fCode <= 0x20) {
      strncpy(buf, keyCodeToString[event->fCode], buflen - 1);
   }
   return n;
}

//______________________________________________________________________________
inline void SplitLong(Long_t ll, Long_t & i1, Long_t & i2)
{
   union {
      Long_t l;
      Int_t i[2];
   } conv;

   conv.l    = 0L;
   conv.i[0] = 0;
   conv.i[1] = 0;

   conv.l = ll;
   i1 = conv.i[0];
   i2 = conv.i[1];
}

//______________________________________________________________________________
inline void AsmLong(Long_t i1, Long_t i2, Long_t & ll)
{
   union {
      Long_t l;
      Int_t i[2];
   } conv;

   conv.i[0] = (Int_t) i1;
   conv.i[1] = (Int_t) i2;
   ll = conv.l;
}

//______________________________________________________________________________
static BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam)
{
   // Make sure the child window is visible.

   ::ShowWindow(hwndChild, SW_SHOWNORMAL);
   GdkWindow *child = gdk_window_lookup(hwndChild);
   if (child)
      ((GdkWindowPrivate *) child)->mapped = TRUE;
   return TRUE;
}

//______________________________________________________________________________
static void _ChangeProperty(HWND w, char *np, char *dp, int n, Atom_t type)
{
   HGLOBAL hMem;
   char *p;

   hMem = ::GetProp(w, np);
   if (hMem != NULL) {
      ::GlobalFree(hMem);
   }
   hMem = ::GlobalAlloc(GHND, n + sizeof(Atom_t));
   p = (char *) ::GlobalLock(hMem);
   memcpy(p, &type, sizeof(Atom_t));
   memcpy(p + sizeof(Atom_t), dp, n);
   ::GlobalUnlock(hMem);
   ::SetProp(w, np, hMem);
   ::GlobalFree(hMem);
}

//______________________________________________________________________________
static void W32ChangeProperty(HWND w, Atom_t property, Atom_t type,
                       int format, int mode, const unsigned char *data,
                       int nelements)
{
   //

   char *atomName;
   char buffer[256];
   int len;
   char propName[32];

   if (mode == GDK_PROP_MODE_REPLACE || mode == GDK_PROP_MODE_PREPEND) {
      len = (int) ::GlobalGetAtomName(property, buffer, sizeof(buffer));
      if ((atomName = (char *) malloc(len + 1)) == NULL) {
         return;
      } else {
         strcpy(atomName, buffer);
      }
      sprintf(propName, "#0x%0.4x", atomName);
      _ChangeProperty(w, propName, (char *) data, nelements, type);
      free(atomName);
   }
}

//______________________________________________________________________________
static int _GetWindowProperty(GdkWindow * id, Atom_t property, Long_t long_offset,
                       Long_t long_length, Bool_t delete_it, Atom_t req_type,
                       Atom_t * actual_type_return,
                       Int_t * actual_format_return, ULong_t * nitems_return,
                       ULong_t * bytes_after_return, UChar_t ** prop_return)
{
   //

   if (!id) return 0;

   char *data, *destPtr;
   char propName[32];
   HGLOBAL handle;
   HWND w;

   w = (HWND) GDK_DRAWABLE_XID(id);

   if (::IsClipboardFormatAvailable(CF_TEXT) && ::OpenClipboard(NULL)) {
      handle = ::GetClipboardData(CF_TEXT);
      if (handle != NULL) {
         data = (char *) ::GlobalLock(handle);
         *nitems_return = strlen(data);
         *prop_return = (UChar_t *) malloc(*nitems_return + 1);
         destPtr = (char *) *prop_return;
         while (*data != '\0') {
            if (*data != '\r') {
               *destPtr = *data;
               destPtr++;
            }
            data++;
         }
         *destPtr = '\0';
         ::GlobalUnlock(handle);
         *actual_type_return = XA_STRING;
         *bytes_after_return = 0;
      }
      ::CloseClipboard();
      return 1;
   }
   if (delete_it) {
      ::RemoveProp(w, propName);
   }
   return 1;
}

//______________________________________________________________________________
static ULong_t GetPixelImage(Drawable_t id, Int_t x, Int_t y)
{
   //

   if (!id) return 0;

   GdkImage *image = (GdkImage *)id;
   ULong_t pixel;

   if (image->depth == 1) {
      pixel = (((char *) image->mem)[y * image->bpl + (x >> 3)] & (1 << (7 - (x & 0x7)))) != 0;
   } else {
      UChar_t *pixelp = (UChar_t *) image->mem + y * image->bpl + x * image->bpp;
      switch (image->bpp) {
         case 1:
            pixel = *pixelp;
            break;
         // Windows is always LSB, no need to check image->byte_order.
         case 2:
            pixel = pixelp[0] | (pixelp[1] << 8);
            break;
         case 3:
            pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
            break;
         case 4:
            pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
            break;
      }
   }
   return pixel;
}

//______________________________________________________________________________
static void CollectImageColors(ULong_t pixel, ULong_t * &orgcolors,
                                 Int_t & ncolors, Int_t & maxcolors)
{
   // Collect in orgcolors all different original image colors.

   if (maxcolors == 0) {
      ncolors = 0;
      maxcolors = 100;
      orgcolors = (ULong_t*) ::operator new(maxcolors*sizeof(ULong_t));
   }

   for (int i = 0; i < ncolors; i++) {
      if (pixel == orgcolors[i]) return;
   }
   if (ncolors >= maxcolors) {
      orgcolors = (ULong_t *) TStorage::ReAlloc(orgcolors,
                                                maxcolors * 2 *
                                                sizeof(ULong_t),
                                                maxcolors *
                                                sizeof(ULong_t));
      maxcolors *= 2;
   }
   orgcolors[ncolors++] = pixel;
}

//______________________________________________________________________________
static char *EventMask2String(UInt_t evmask)
{
   // debug function for printing event mask

   static char bfr[500];
   char *p = bfr;

   *p = '\0';
#define BITmask(x) \
  if (evmask & k##x##Mask) \
    p += sprintf (p, "%s" #x, (p > bfr ? " " : ""))
   BITmask(Exposure);
   BITmask(PointerMotion);
   BITmask(ButtonMotion);
   BITmask(ButtonPress);
   BITmask(ButtonRelease);
   BITmask(KeyPress);
   BITmask(KeyRelease);
   BITmask(EnterWindow);
   BITmask(LeaveWindow);
   BITmask(FocusChange);
   BITmask(StructureNotify);
#undef BITmask

   return bfr;
}

///////////////////////////////////////////////////////////////////////////////
class TGWin32MainThread {

public:
   void     *fHandle;                     // handle of server (aka command) thread
   DWORD    fId;                          // id of server (aka command) thread
   static LPCRITICAL_SECTION  fCritSec;      // general mutex
   static LPCRITICAL_SECTION  fMessageMutex; // message queue mutex

   TGWin32MainThread();
   ~TGWin32MainThread();
   static void LockMSG();
   static void UnlockMSG();
};

TGWin32MainThread *gMainThread = 0;
LPCRITICAL_SECTION TGWin32MainThread::fCritSec = 0;
LPCRITICAL_SECTION TGWin32MainThread::fMessageMutex = 0;


//______________________________________________________________________________
TGWin32MainThread::~TGWin32MainThread()
{
   // dtor

   if (fCritSec) {
      ::LeaveCriticalSection(fCritSec);
      ::DeleteCriticalSection(fCritSec);
      delete fCritSec;
   }
   fCritSec = 0;

   if (fMessageMutex) {
      ::LeaveCriticalSection(fMessageMutex);
      ::DeleteCriticalSection(fMessageMutex);
      delete fMessageMutex;
   }
   fMessageMutex = 0;

   if(fHandle) {
      ::PostThreadMessage(fId, WM_QUIT, 0, 0);
      ::CloseHandle(fHandle);
   }
   fHandle = 0;
}

//______________________________________________________________________________
void TGWin32MainThread::LockMSG()
{
   // lock message queue

   if (fMessageMutex) ::EnterCriticalSection(fMessageMutex);
}

//______________________________________________________________________________
void TGWin32MainThread::UnlockMSG()
{
   // unlock message queue

   if (fMessageMutex) ::LeaveCriticalSection(fMessageMutex);
}

///////////////////////////////////////////////////////////////////////////////
class TGWin32RefreshTimer : public TTimer {

public:
   TGWin32RefreshTimer() : TTimer(10, kTRUE) { if (gSystem) gSystem->AddTimer(this); }
   ~TGWin32RefreshTimer() { if (gSystem) gSystem->RemoveTimer(this); }
   Bool_t Notify()
   {
      Reset();
      MSG msg;

      while (::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE)) {
         ::PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE);
         if (!gVirtualX)
            Sleep(200); // avoid start-up race
         if (gVirtualX)
            ((TGWin32*)gVirtualX)->GUIThreadMessageFunc(&msg);
      }
      return kFALSE;
   }
};
/*
//______________________________________________________________________________
static DWORD WINAPI MessageProcessingLoop(void *p)
{
   // thread for processing windows messages (aka Main/Server thread)

   MSG msg;
   Int_t erret;
   Bool_t endLoop = kFALSE;
   TGWin32RefreshTimer *refersh = 0;

   // force to create message queue
   ::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);

   // periodically we refresh windows
   // Don't create refresh timer if the application has been created inside PVSS
   if (gApplication) {
      TString arg = gSystem->BaseName(gApplication->Argv(0));
      if (!arg.Contains("PVSS"))
         refersh = new TGWin32RefreshTimer();
   }

   while (!endLoop) {
      erret = ::GetMessage(&msg, NULL, NULL, NULL);
      if (erret <= 0) endLoop = kTRUE;
      endLoop = MessageProcessingFunc(&msg);
   }

   TGWin32::Instance()->CloseDisplay();
   if (refersh)
      delete refersh;

   // exit thread
   if (erret == -1) {
      erret = ::GetLastError();
      Error("MsgLoop", "Error in GetMessage");
      ::ExitThread(-1);
   } else {
      ::ExitThread(0);
   }
   return 0;
}
*/

Bool_t GUIThreadMessageWrapper(MSG* msg)
{
   // Static wrapper for handling GUI messages.
   // Forwards from TWinNTSystem's GUIThreadMessageProcessingLoop()
   // to TGWin32::GUIThreadMessageFunc()

   return ((TGWin32*)gVirtualX)->GUIThreadMessageFunc(msg);
}

//______________________________________________________________________________
TGWin32MainThread::TGWin32MainThread()
{
   // constructor

   fCritSec = new CRITICAL_SECTION;
   ::InitializeCriticalSection(fCritSec);
   fMessageMutex = new CRITICAL_SECTION;
   ::InitializeCriticalSection(fMessageMutex);
   fHandle = ((TWinNTSystem*)gSystem)->GetGUIThreadHandle();
   fId = ((TWinNTSystem*)gSystem)->GetGUIThreadId();
   ((TWinNTSystem*)gSystem)->SetGUIThreadMsgHandler(GUIThreadMessageWrapper);
}

} // unnamed namespace

///////////////////////// TGWin32 implementation ///////////////////////////////
ClassImp(TGWin32)

//______________________________________________________________________________
TGWin32::TGWin32(): fRefreshTimer(0)
{
   // Default constructor.

   fScreenNumber = 0;
   fWindows      = 0;
   fColors       = 0;
}

//______________________________________________________________________________
TGWin32::TGWin32(const char *name, const char *title) : TVirtualX(name,title), fRefreshTimer(0)
{
   // Normal Constructor.

   fScreenNumber = 0;
   fHasTTFonts = kFALSE;
   fUseSysPointers = kFALSE;
   fTextAlignH = 1;
   fTextAlignV = 1;
   fTextAlign = 7;
   fTextMagnitude = 1;
   fCharacterUpX = 1;
   fCharacterUpY = 1;
   fDrawMode = kCopy;
   fWindows = 0;
   fMaxNumberOfWindows = 10;
   fXEvent = 0;
   fFillColorModified = kFALSE;
   fFillStyleModified = kFALSE;
   fLineColorModified = kFALSE;
   fPenModified = kFALSE;
   fMarkerStyleModified = kFALSE;
   fMarkerColorModified = kFALSE;

   fWindows = (XWindow_t*) TStorage::Alloc(fMaxNumberOfWindows*sizeof(XWindow_t));
   for (int i = 0; i < fMaxNumberOfWindows; i++) fWindows[i].open = 0;

   fColors = new TExMap;

   if (gApplication) {
      TString arg = gSystem->BaseName(gApplication->Argv(0));
      if (!arg.Contains("PVSS"))
         fRefreshTimer = new TGWin32RefreshTimer();
   } else {
      fRefreshTimer = new TGWin32RefreshTimer();
   }

   // initialize GUI thread and proxy objects
   if (!gROOT->IsBatch() && !gMainThread) {
      gMainThread = new TGWin32MainThread();
      TGWin32ProxyBase::fgMainThreadId = ::GetCurrentThreadId(); // gMainThread->fId;
      TGWin32VirtualXProxy::fgRealObject = this;
      gPtr2VirtualX = &TGWin32VirtualXProxy::ProxyObject;
#ifdef OLD_THREAD_IMPLEMENTATION
      gPtr2Interpreter = &TGWin32InterpreterProxy::ProxyObject;
#endif
   }
}

//______________________________________________________________________________
TGWin32::~TGWin32()
{
   // destructor.

   CloseDisplay();
   if (fRefreshTimer)
      delete fRefreshTimer;
   if (!fColors) return;
   Long64_t key, value;
   TExMapIter it(fColors);
   while (it.Next(key, value)) {
      XColor_t *col = (XColor_t *) value;
      delete col;
   }
   delete fColors;
}

//______________________________________________________________________________
VOID CALLBACK MyTimerProc(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime)
{
   // Windows timer handling events while moving/resizing windows

   gSystem->ProcessEvents();
   //gVirtualX->UpdateWindow(1); // cause problems with OpenGL in pad...
} 

//______________________________________________________________________________
Bool_t TGWin32::GUIThreadMessageFunc(MSG* msg)
{
   // Message processing function for the GUI thread.
   // Kicks in once TGWin32 becomes active, and "replaces" the dummy one
   // in TWinNTSystem; see TWinNTSystem.cxx's GUIThreadMessageProcessingLoop().

   Bool_t ret = kFALSE;
   static Int_t m_timer = 0;

   if ( (msg->message == WM_NCLBUTTONDOWN) ) {
      if (m_timer == 0)
         m_timer = SetTimer(NULL, 1, 20, (TIMERPROC) MyTimerProc);
   }
   else if (msg->message == WM_NCMOUSELEAVE ) {
      if (m_timer) {
         KillTimer(NULL, m_timer);
      }
      m_timer = 0;
   }

   if (msg->message == TGWin32ProxyBase::fgPostMessageId) {
      if (msg->wParam) {
         TGWin32ProxyBase *proxy = (TGWin32ProxyBase*)msg->wParam;
         proxy->ExecuteCallBack(kTRUE);
      } else {
         ret = kTRUE;
      }
   } else if (msg->message == TGWin32ProxyBase::fgPingMessageId) {
      TGWin32ProxyBase::GlobalUnlock();
   } else {
      //if ( (msg->message >= WM_NCMOUSEMOVE) &&
      //     (msg->message <= WM_NCMBUTTONDBLCLK) ) {
      //   TGWin32ProxyBase::GlobalLock();
      //}
      TGWin32MainThread::LockMSG();
      TranslateMessage(msg);
      DispatchMessage(msg);
      TGWin32MainThread::UnlockMSG();
   }
   return ret;
}

//______________________________________________________________________________
Bool_t TGWin32::IsCmdThread() const
{
   // returns kTRUE if we are inside cmd/server thread

#ifdef OLD_THREAD_IMPLEMENTATION
   return ((::GetCurrentThreadId() == TGWin32ProxyBase::fgMainThreadId) ||
           (::GetCurrentThreadId() == TGWin32ProxyBase::fgUserThreadId));
#else
   return kTRUE;
#endif
}

//______________________________________________________________________________
void TGWin32::CloseDisplay()
{
   // close display (terminate server/gMainThread thread)

   // disable any processing while exiting
   TGWin32ProxyBase::GlobalLock();

   // terminate server thread
   gPtr2VirtualX = 0;
   gPtr2Interpreter = 0;
   gVirtualX = TGWin32VirtualXProxy::RealObject();
   gInterpreter = TGWin32InterpreterProxy::RealObject();

   // The lock above does not work, so at least
   // minimize the risk
   TGWin32MainThread *delThread = gMainThread;
   if (gMainThread) {
      gMainThread = 0;
      delete delThread;
   }

   TGWin32ProxyBase::fgMainThreadId = 0;

   // terminate ROOT logo splash thread
   TWin32SplashThread *delSplash = gSplash;
   if (gSplash) {
      gSplash = 0;
      delete delSplash;
   }

   if (fWindows) TStorage::Dealloc(fWindows);
   fWindows = 0;

   if (fXEvent) gdk_event_free((GdkEvent*)fXEvent);

   TGWin32ProxyBase::GlobalUnlock();

   gROOT->SetBatch(kTRUE); // no GUI is possible
}

//______________________________________________________________________________
void  TGWin32::Lock()
{
   //

   if (gMainThread && gMainThread->fCritSec) ::EnterCriticalSection(gMainThread->fCritSec);
}

//______________________________________________________________________________
void TGWin32::Unlock()
{
   //

   if (gMainThread && gMainThread->fCritSec) ::LeaveCriticalSection(gMainThread->fCritSec);
}

//______________________________________________________________________________
Bool_t TGWin32::Init(void *display)
{
   // Initialize Win32 system. Returns kFALSE in case of failure.

   if (!gdk_initialized) {
      if (!gdk_init_check(NULL, NULL)) return kFALSE;
      gdk_initialized = true;
   }

   if (!gClipboardAtom) {
      gClipboardAtom = gdk_atom_intern("CLIPBOARD", kFALSE);
   }

   return kTRUE;
}

//______________________________________________________________________________
Int_t TGWin32::OpenDisplay(const char *dpyName)
{
   // Open the display. Return -1 if the opening fails, 0 when ok.

   GdkPixmap *pixmp1, *pixmp2;
   GdkColor fore, back;
   GdkColor color;
   GdkGCValues gcvals;
   int i;

   if (!Init((void*)dpyName)) {
      return -1;
   }

   if (gDebug <= 4) {
      gdk_debug_level = gDebug;
   } else {
      gdk_debug_level = 0;
   }

   fore.red = fore.green = fore.blue = 0;
   back.red = back.green = back.blue = 0;
   color.red = color.green = color.blue = 0;
      
   fScreenNumber = 0;           //DefaultScreen(fDisplay);
   fVisual = gdk_visual_get_best();
   fColormap = gdk_colormap_get_system();
   fDepth = gdk_visual_get_best_depth();

   GetColor(1).fDefined = kTRUE; // default foreground
   gdk_color_black((GdkColormap *)fColormap, &GetColor(1).color);

   GetColor(0).fDefined = kTRUE; // default background
   gdk_color_white((GdkColormap *)fColormap, &GetColor(0).color);

   // Create primitives graphic contexts
   for (i = 0; i < kMAXGC; i++) {
      gGClist[i]  = gdk_gc_new(GDK_ROOT_PARENT());
      gdk_gc_set_foreground(gGClist[i], &GetColor(1).color);
      gdk_gc_set_background(gGClist[i], &GetColor(0).color);
   }

   gGCline = gGClist[0];        // PolyLines
   gGCmark = gGClist[1];        // PolyMarker
   gGCfill = gGClist[2];        // Fill areas
   gGCtext = gGClist[3];        // Text
   gGCinvt = gGClist[4];        // Inverse text
   gGCdash = gGClist[5];        // Dashed lines
   gGCpxmp = gGClist[6];        // Pixmap management

   gdk_gc_get_values(gGCtext, &gcvals);
   gdk_gc_set_foreground(gGCinvt, &gcvals.background);
   gdk_gc_set_background(gGCinvt, &gcvals.foreground);

   // Create input echo graphic context
   GdkGCValues echov;
   gdk_color_black(fColormap, &echov.foreground);	// = BlackPixel(fDisplay, fScreenNumber);
   gdk_color_white(fColormap, &echov.background);	// = WhitePixel(fDisplay, fScreenNumber);
   echov.function = GDK_INVERT;
   echov.subwindow_mode = GDK_CLIP_BY_CHILDREN;
   gGCecho =
       gdk_gc_new_with_values((GdkWindow *) GDK_ROOT_PARENT(), &echov,
                              (GdkGCValuesMask) (GDK_GC_FOREGROUND |
                                                 GDK_GC_BACKGROUND |
                                                 GDK_GC_FUNCTION |
                                                 GDK_GC_SUBWINDOW));
   // Create a null cursor
   pixmp1 = gdk_bitmap_create_from_data(GDK_ROOT_PARENT(),
                                       (const char *)null_cursor_bits, 16,16);

   pixmp2 = gdk_bitmap_create_from_data(GDK_ROOT_PARENT(),
                                       (const char *)null_cursor_bits, 16, 16);

   gNullCursor = gdk_cursor_new_from_pixmap((GdkDrawable *)pixmp1, (GdkDrawable *)pixmp2,
                                             &fore, &back, 0, 0);
   // Create cursors
   if (gEnv->GetValue("Win32.UseSysPointers", 0)) {
      fUseSysPointers = kTRUE;
      fCursors[kBottomLeft] = gdk_syscursor_new((ULong_t)IDC_SIZENESW);
      fCursors[kBottomRight] = gdk_syscursor_new((ULong_t)IDC_SIZENWSE);
      fCursors[kTopLeft] = gdk_syscursor_new((ULong_t)IDC_SIZENWSE);
      fCursors[kTopRight] = gdk_syscursor_new((ULong_t)IDC_SIZENESW);
      fCursors[kBottomSide] =  gdk_syscursor_new((ULong_t)IDC_SIZENS);
      fCursors[kLeftSide] = gdk_syscursor_new((ULong_t)IDC_SIZEWE);
      fCursors[kTopSide] = gdk_syscursor_new((ULong_t)IDC_SIZENS);
      fCursors[kRightSide] = gdk_syscursor_new((ULong_t)IDC_SIZEWE);
      fCursors[kMove] = gdk_syscursor_new((ULong_t)IDC_SIZEALL);
      fCursors[kCross] =gdk_syscursor_new((ULong_t)IDC_CROSS);
      fCursors[kArrowHor] = gdk_syscursor_new((ULong_t)IDC_SIZEWE);
      fCursors[kArrowVer] = gdk_syscursor_new((ULong_t)IDC_SIZENS);
      fCursors[kHand] = gdk_syscursor_new((ULong_t)IDC_HAND);
      fCursors[kPointer] = gdk_syscursor_new((ULong_t)IDC_ARROW);
      fCursors[kCaret] =  gdk_syscursor_new((ULong_t)IDC_IBEAM);
      fCursors[kWatch] = gdk_syscursor_new((ULong_t)IDC_WAIT);
      fCursors[kNoDrop] = gdk_syscursor_new((ULong_t)IDC_NO);
   }
   else {
      fUseSysPointers = kFALSE;
      fCursors[kBottomLeft] = gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER);
      fCursors[kBottomRight] = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER);
      fCursors[kTopLeft] = gdk_cursor_new(GDK_TOP_LEFT_CORNER);
      fCursors[kTopRight] = gdk_cursor_new(GDK_TOP_RIGHT_CORNER);
      fCursors[kBottomSide] =  gdk_cursor_new(GDK_BOTTOM_SIDE);
      fCursors[kLeftSide] = gdk_cursor_new(GDK_LEFT_SIDE);
      fCursors[kTopSide] = gdk_cursor_new(GDK_TOP_SIDE);
      fCursors[kRightSide] = gdk_cursor_new(GDK_RIGHT_SIDE);
      fCursors[kMove] = gdk_cursor_new(GDK_FLEUR);
      fCursors[kCross] =gdk_cursor_new(GDK_CROSSHAIR);
      fCursors[kArrowHor] = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
      fCursors[kArrowVer] = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
      fCursors[kHand] = gdk_cursor_new(GDK_HAND2);
      fCursors[kPointer] = gdk_cursor_new(GDK_LEFT_PTR);
      fCursors[kCaret] =  gdk_cursor_new(GDK_XTERM);
      //fCursors[kWatch] = gdk_cursor_new(GDK_WATCH);
      fCursors[kWatch] = gdk_cursor_new(GDK_BUSY);
      fCursors[kNoDrop] = gdk_cursor_new(GDK_PIRATE);
   }
   fCursors[kRotate] = gdk_cursor_new(GDK_EXCHANGE);
   fCursors[kArrowRight] = gdk_cursor_new(GDK_ARROW);

   // Setup color information
   fRedDiv = fGreenDiv = fBlueDiv = fRedShift = fGreenShift = fBlueShift = -1;

   if ( gdk_visual_get_best_type() == GDK_VISUAL_TRUE_COLOR) {
      int i;
      for (i = 0; i < int(sizeof(fVisual->blue_mask)*kBitsPerByte); i++) {
         if (fBlueShift == -1 && ((fVisual->blue_mask >> i) & 1)) {
            fBlueShift = i;
         }
         if ((fVisual->blue_mask >> i) == 1) {
            fBlueDiv = sizeof(UShort_t)*kBitsPerByte - i - 1 + fBlueShift;
            break;
         }
      }
      for (i = 0; i < int(sizeof(fVisual->green_mask)*kBitsPerByte); i++) {
         if (fGreenShift == -1 && ((fVisual->green_mask >> i) & 1)) {
            fGreenShift = i;
         }
         if ((fVisual->green_mask >> i) == 1) {
            fGreenDiv = sizeof(UShort_t)*kBitsPerByte - i - 1 + fGreenShift;
            break;
         }
      }
      for (i = 0; i < int(sizeof(fVisual->red_mask)*kBitsPerByte); i++) {
         if (fRedShift == -1 && ((fVisual->red_mask >> i) & 1)) {
            fRedShift = i;
         }
         if ((fVisual->red_mask >> i) == 1) {
            fRedDiv = sizeof(UShort_t)*kBitsPerByte - i - 1 + fRedShift;
            break;
         }
      }
   }

   SetName("Win32TTF");
   SetTitle("ROOT interface to Win32 with TrueType fonts");

   if (!TTF::IsInitialized()) TTF::Init();

   if (fDepth > 8) {
      TTF::SetSmoothing(kTRUE);
   } else {
      TTF::SetSmoothing(kFALSE);
   }

   TGWin32VirtualXProxy::fMaxResponseTime = 1000;
   fHasTTFonts = kTRUE;
   return 0;
}

//______________________________________________________________________________
Bool_t TGWin32::AllocColor(GdkColormap *cmap, GdkColor *color)
{
   // Allocate color in colormap. If we are on an <= 8 plane machine
   // we will use XAllocColor. If we are on a >= 15 (15, 16 or 24) plane
   // true color machine we will calculate the pixel value using:
   // for 15 and 16 bit true colors have 6 bits precision per color however
   // only the 5 most significant bits are used in the color index.
   // Except for 16 bits where green uses all 6 bits. I.e.:
   //   15 bits = rrrrrgggggbbbbb
   //   16 bits = rrrrrggggggbbbbb
   // for 24 bits each r, g and b are represented by 8 bits.
   //
   // Since all colors are set with a max of 65535 (16 bits) per r, g, b
   // we just right shift them by 10, 11 and 10 bits for 16 planes, and
   // (10, 10, 10 for 15 planes) and by 8 bits for 24 planes.
   // Returns kFALSE in case color allocation failed.

   if (fRedDiv == -1) {
      if ( gdk_color_alloc((GdkColormap *)cmap, (GdkColor *)color) ) return kTRUE;
   } else {
      color->pixel = (color->red   >> fRedDiv)   << fRedShift |
                     (color->green >> fGreenDiv) << fGreenShift |
                     (color->blue  >> fBlueDiv)  << fBlueShift;
      return kTRUE;
   }

   return kFALSE;
}

//______________________________________________________________________________
void TGWin32::QueryColors(GdkColormap *cmap, GdkColor *color, Int_t ncolors)
{
   // Returns the current RGB value for the pixel in the XColor structure.

   ULong_t r, g, b;

   if (fRedDiv == -1) {
      GdkColorContext *cc = gdk_color_context_new(gdk_visual_get_system(), cmap);
      gdk_color_context_query_colors(cc, color, ncolors);
      gdk_color_context_free(cc);
   } else {
      for (Int_t i = 0; i < ncolors; i++) {
         r = (color[i].pixel & fVisual->red_mask) >> fRedShift;
         color[i].red = UShort_t(r*kBIGGEST_RGB_VALUE/(fVisual->red_mask >> fRedShift));

         g = (color[i].pixel & fVisual->green_mask) >> fGreenShift;
         color[i].green = UShort_t(g*kBIGGEST_RGB_VALUE/(fVisual->green_mask >> fGreenShift));

         b = (color[i].pixel & fVisual->blue_mask) >> fBlueShift;
         color[i].blue = UShort_t(b*kBIGGEST_RGB_VALUE/(fVisual->blue_mask >> fBlueShift));
      }
   }
}

//______________________________________________________________________________
void TGWin32::Align(void)
{
   // Compute alignment variables. The alignment is done on the horizontal string
   // then the rotation is applied on the alignment variables.
   // SetRotation and LayoutGlyphs should have been called before.

   EAlign align = (EAlign) fTextAlign;

   // vertical alignment
   if (align == kTLeft || align == kTCenter || align == kTRight) {
      fAlign.y = TTF::GetAscent();
   } else if (align == kMLeft || align == kMCenter || align == kMRight) {
      fAlign.y = TTF::GetAscent()/2;
   } else {
      fAlign.y = 0;
   }
   // horizontal alignment
   if (align == kTRight || align == kMRight || align == kBRight) {
      fAlign.x = TTF::GetWidth();
   } else if (align == kTCenter || align == kMCenter || align == kBCenter) {
      fAlign.x = TTF::GetWidth()/2;
   } else {
      fAlign.x = 0;
   }

   FT_Vector_Transform(&fAlign, TTF::GetRotMatrix());
   fAlign.x = fAlign.x >> 6;
   fAlign.y = fAlign.y >> 6;
}

//______________________________________________________________________________
void TGWin32::DrawImage(FT_Bitmap *source, ULong_t fore, ULong_t back,
                         GdkImage *xim, Int_t bx, Int_t by)
{
   // Draw FT_Bitmap bitmap to xim image at position bx,by using specified
   // foreground color.

   UChar_t d = 0, *s = source->buffer;

   if (TTF::GetSmoothing()) {

      static GdkColor col[5];
      GdkColor *bcol = 0, *bc;
      Int_t    x, y;

      // background kClear, i.e. transparent, we take as background color
      // the average of the rgb values of all pixels covered by this character
      if (back == (ULong_t) -1 && (UInt_t)source->width) {
         ULong_t r, g, b;
         Int_t   dots, dotcnt;
         const Int_t maxdots = 50000;

         dots = Int_t(source->width * source->rows);
         dots = dots > maxdots ? maxdots : dots;
         bcol = new GdkColor[dots];
         if (!bcol) return;

         bc = bcol;
         dotcnt = 0;
         for (y = 0; y < (int) source->rows; y++) {
            for (x = 0; x < (int) source->width; x++, bc++) {
               bc->pixel = GetPixelImage((Drawable_t)xim, bx + x, by + y);
               if (++dotcnt >= maxdots) break;
            }
         }
         QueryColors(fColormap, bcol, dots);
         r = g = b = 0;
         bc = bcol;
         dotcnt = 0;
         for (y = 0; y < (int) source->rows; y++) {
            for (x = 0; x < (int) source->width; x++, bc++) {
               r += bc->red;
               g += bc->green;
               b += bc->blue;
               if (++dotcnt >= maxdots) break;
            }
         }
         if (dots != 0) {
            r /= dots;
            g /= dots;
            b /= dots;
         }
         bc = &col[0];
         if (bc->red == r && bc->green == g && bc->blue == b) {
            bc->pixel = back;
         } else {
            bc->pixel = ~back;
            bc->red   = (UShort_t) r;
            bc->green = (UShort_t) g;
            bc->blue  = (UShort_t) b;
         }
      }
      delete [] bcol;

      // if fore or background have changed from previous character
      // recalculate the 3 smooting colors (interpolation between fore-
      // and background colors)
      if (fore != col[4].pixel || back != col[0].pixel) {
         col[4].pixel = fore;
         if (back != (ULong_t) -1) {
            col[3].pixel = back;
            QueryColors(fColormap, &col[3], 2);
            col[0] = col[3];
         } else {
            QueryColors(fColormap, &col[4], 1);
         }

         // interpolate between fore and backgound colors
         for (x = 3; x > 0; x--) {
            col[x].red   = (col[4].red  *x + col[0].red  *(4-x)) /4;
            col[x].green = (col[4].green*x + col[0].green*(4-x)) /4;
            col[x].blue  = (col[4].blue *x + col[0].blue *(4-x)) /4;
            if (!AllocColor(fColormap, &col[x])) {
               Warning("DrawImage", "cannot allocate smoothing color");
               col[x].pixel = col[x+1].pixel;
            }
         }
      }

      // put smoothed character, character pixmap values are an index
      // into the 5 colors used for aliasing (4 = foreground, 0 = background)
      for (y = 0; y < (int) source->rows; y++) {
         for (x = 0; x < (int) source->width; x++) {
            d = *s++ & 0xff;
            d = ((d + 10) * 5) / 256;
            if (d > 4) d = 4;
            if (d && x < (int) source->width) {
               ULong_t p = col[d].pixel;
               PutPixel((Drawable_t)xim, bx + x, by + y, p);
            }
         }
      }
   } else {
      // no smoothing, just put character using foreground color
      UChar_t* row=s;
      for (int y = 0; y < (int) source->rows; y++) {
         int n = 0;
         s = row;
         for (int x = 0; x < (int) source->width; x++) {
            if (n == 0) d = *s++;
            if (TESTBIT(d,7-n)) {
               PutPixel((Drawable_t)xim, bx + x, by + y, fore);
            }
            if (++n == (int) kBitsPerByte) n = 0;
         }
         row += source->pitch;
      }
   }
}

//______________________________________________________________________________
void TGWin32::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn,
                       const char *text, ETextMode mode)
{
   // Draw text using TrueType fonts. If TrueType fonts are not available the
   // text is drawn with TGWin32::DrawText.

   if (!TTF::IsInitialized()) TTF::Init();
   TTF::SetRotationMatrix(angle);
   TTF::PrepareString(text);
   TTF::LayoutGlyphs();
   Align();
   RenderString(x, y, mode);
}

//______________________________________________________________________________
void TGWin32::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn,
                       const wchar_t *text, ETextMode mode)
{
   // Draw text using TrueType fonts. If TrueType fonts are not available the
   // text is drawn with TGWin32::DrawText.

   if (!TTF::IsInitialized()) TTF::Init();
   TTF::SetRotationMatrix(angle);
   TTF::PrepareString(text);
   TTF::LayoutGlyphs();
   Align();
   RenderString(x, y, mode);
}

//______________________________________________________________________________
GdkImage *TGWin32::GetBackground(Int_t x, Int_t y, UInt_t w, UInt_t h)
{
   // Get the background of the current window in an XImage.

   Window_t cws = GetCurrentWindow();
   UInt_t width;
   UInt_t height;
   Int_t xy;
   gVirtualX->GetWindowSize(cws, xy, xy, width, height);

   if (x < 0) {
      w += x;
      x  = 0;
   }
   if (y < 0) {
      h += y;
      y  = 0;
   }

   if (x+w > width)  w = width - x;
   if (y+h > height) h = height - y;

   return gdk_image_get((GdkDrawable*)cws, x, y, w, h);
}

//______________________________________________________________________________
Bool_t TGWin32::IsVisible(Int_t x, Int_t y, UInt_t w, UInt_t h)
{
   // Test if there is really something to render

   Window_t cws = GetCurrentWindow();
   UInt_t width;
   UInt_t height;
   Int_t xy;
   gVirtualX->GetWindowSize(cws, xy, xy, width, height);

   // If w or h is 0, very likely the string is only blank characters
   if ((int)w == 0 || (int)h == 0)  return kFALSE;

   // If string falls outside window, there is probably no need to draw it.
   if (x + (int)w <= 0 || x >= (int)width)  return kFALSE;
   if (y + (int)h <= 0 || y >= (int)height) return kFALSE;

   return kTRUE;
}

//______________________________________________________________________________
void TGWin32::RenderString(Int_t x, Int_t y, ETextMode mode)
{
   // Perform the string rendering in the pad.
   // LayoutGlyphs should have been called before.

   TTGlyph* glyph = TTF::GetGlyphs();
   GdkGCValues gcvals;

   // compute the size and position of the XImage that will contain the text
   Int_t Xoff = 0; if (TTF::GetBox().xMin < 0) Xoff = -TTF::GetBox().xMin;
   Int_t Yoff = 0; if (TTF::GetBox().yMin < 0) Yoff = -TTF::GetBox().yMin;
   Int_t w    = TTF::GetBox().xMax + Xoff;
   Int_t h    = TTF::GetBox().yMax + Yoff;
   Int_t x1   = x-Xoff-fAlign.x;
   Int_t y1   = y+Yoff+fAlign.y-h;

   if (!IsVisible(x1, y1, w, h)) {
       return;
   }

   // create the XImage that will contain the text
   UInt_t depth = fDepth;
   GdkImage *xim  = gdk_image_new(GDK_IMAGE_SHARED, gdk_visual_get_best(), w, h);

   // use malloc since Xlib will use free() in XDestroyImage
//   xim->data = (char *) malloc(xim->bytes_per_line * h);
//   memset(xim->data, 0, xim->bytes_per_line * h);

   ULong_t   pixel;
   ULong_t   bg;

   gdk_gc_get_values((GdkGC*)GetGC(3), &gcvals);

   // get the background
   if (mode == kClear) {
      // if mode == kClear we need to get an image of the background
      GdkImage *bim = GetBackground(x1, y1, w, h);
      if (!bim) {
         Error("DrawText", "error getting background image");
         return;
      }

      // and copy it into the text image
      Int_t xo = 0, yo = 0;
      if (x1 < 0) xo = -x1;
      if (y1 < 0) yo = -y1;

      for (int yp = 0; yp < (int) bim->height; yp++) {
         for (int xp = 0; xp < (int) bim->width; xp++) {
            pixel = GetPixelImage((Drawable_t)bim, xp, yp);
            PutPixel((Drawable_t)xim, xo+xp, yo+yp, pixel);
         }
      }

      gdk_image_unref((GdkImage *)bim);

      bg = (ULong_t) -1;
   } else {
      // if mode == kOpaque its simple, we just draw the background

      GdkImage *bim = GetBackground(x1, y1, w, h);
      if (!bim) {
         pixel = gcvals.background.pixel;
      } else {
         pixel = GetPixelImage((Drawable_t)bim, 0, 0);
      }
      Int_t xo = 0, yo = 0;
      if (x1 < 0) xo = -x1;
      if (y1 < 0) yo = -y1;

      for (int yp = 0; yp < h; yp++) {
         for (int xp = 0; xp < (int) w; xp++) {
            PutPixel((Drawable_t)xim, xo+xp, yo+yp, pixel);
         }
      }
      if (bim) {
         gdk_image_unref((GdkImage *)bim);
         bg = (ULong_t) -1;
      } else {
         bg = pixel;
      }
   }

   // paint the glyphs in the XImage
   glyph = TTF::GetGlyphs();
   for (int n = 0; n < TTF::GetNumGlyphs(); n++, glyph++) {
      if (FT_Glyph_To_Bitmap(&glyph->fImage,
                             TTF::GetSmoothing() ? ft_render_mode_normal
                                              : ft_render_mode_mono,
                             0, 1 )) continue;
      FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph->fImage;
      FT_Bitmap*     source = &bitmap->bitmap;
      Int_t          bx, by;

      bx = bitmap->left+Xoff;
      by = h - bitmap->top-Yoff;
      DrawImage(source, gcvals.foreground.pixel, bg, xim, bx, by);
   }

   // put the Ximage on the screen
   Window_t cws = GetCurrentWindow();
   gdk_draw_image((GdkDrawable *)cws, GetGC(6), xim, 0, 0, x1, y1, w, h);

   gdk_image_unref(xim);
}

//______________________________________________________________________________
void TGWin32::SetTextFont(Font_t fontnumber)
{
   // Set specified font.

   fTextFont = fontnumber;
   TTF::SetTextFont(fontnumber);
}

//______________________________________________________________________________
Int_t TGWin32::SetTextFont(char *fontname, ETextSetMode mode)
{
   // Set text font to specified name.
   // mode       : loading flag
   // mode=0     : search if the font exist (kCheck)
   // mode=1     : search the font and load it if it exists (kLoad)
   // font       : font name
   //
   // Set text font to specified name. This function returns 0 if
   // the specified font is found, 1 if not.

   return TTF::SetTextFont(fontname);
}

//______________________________________________________________________________
void TGWin32::SetTextSize(Float_t textsize)
{
   // Set current text size.

   fTextSize = textsize;
   TTF::SetTextSize(textsize);
}

//______________________________________________________________________________
void TGWin32::ClearWindow()
{
   // Clear current window.

   if (!fWindows) return;

   if (!gCws->ispixmap && !gCws->double_buffer) {
      gdk_window_set_background(gCws->drawing, (GdkColor *) & GetColor(0).color);
      gdk_window_clear(gCws->drawing);
      GdiFlush();
   } else {
      SetColor(gGCpxmp, 0);
      gdk_win32_draw_rectangle(gCws->drawing, gGCpxmp, 1,
                         0, 0, gCws->width, gCws->height);
      SetColor(gGCpxmp, 1);
   }
}

//______________________________________________________________________________
void TGWin32::ClosePixmap()
{
   // Delete current pixmap.

   CloseWindow1();
}

//______________________________________________________________________________
void TGWin32::CloseWindow()
{
   // Delete current window.

   CloseWindow1();
}

//______________________________________________________________________________
void TGWin32::CloseWindow1()
{
   // Delete current window.

   int wid;

   if (gCws->ispixmap) {
      gdk_pixmap_unref(gCws->window);
   } else {
      gdk_window_destroy(gCws->window, kTRUE);
   }

   if (gCws->buffer) {
      gdk_pixmap_unref(gCws->buffer);
   }
   if (gCws->new_colors) {
      gdk_colormap_free_colors((GdkColormap *) fColormap,
                               (GdkColor *)gCws->new_colors, gCws->ncolors);

      delete [] gCws->new_colors;
      gCws->new_colors = 0;
   }

   GdiFlush();
   gCws->open = 0;

   if (!fWindows) return;

   // make first window in list the current window
   for (wid = 0; wid < fMaxNumberOfWindows; wid++) {
      if (fWindows[wid].open) {
         gCws = &fWindows[wid];
         return;
      }
   }
   gCws = 0;
}

//______________________________________________________________________________
void TGWin32::CopyPixmap(int wid, int xpos, int ypos)
{
   // Copy the pixmap wid at the position xpos, ypos in the current window.

   if (!fWindows) return;

   gTws = &fWindows[wid];
   gdk_window_copy_area(gCws->drawing, gGCpxmp, xpos, ypos, gTws->drawing,
                        0, 0, gTws->width, gTws->height);
   GdiFlush();
}

//______________________________________________________________________________
void TGWin32::DrawBox(int x1, int y1, int x2, int y2, EBoxMode mode)
{
   // Draw a box.
   // mode=0 hollow  (kHollow)
   // mode=1 solid   (kSolid)

   if (!fWindows) return;

   Int_t x = TMath::Min(x1, x2);
   Int_t y = TMath::Min(y1, y2);
   Int_t w = TMath::Abs(x2 - x1);
   Int_t h = TMath::Abs(y2 - y1);

   switch (mode) {

   case kHollow:
      if (fLineColorModified) UpdateLineColor();
      if (fPenModified) UpdateLineStyle();
      gdk_win32_draw_rectangle(gCws->drawing, gGCline, 0, x, y, w, h);
      break;

   case kFilled:
      if (fFillStyleModified) UpdateFillStyle();
      if (fFillColorModified) UpdateFillColor();
      gdk_win32_draw_rectangle(gCws->drawing, gGCfill, 1, x, y, w, h);
      break;

   default:
      break;
   }
}

//______________________________________________________________________________
void TGWin32::DrawCellArray(Int_t x1, Int_t y1, Int_t x2, Int_t y2,
                            Int_t nx, Int_t ny, Int_t *ic)
{
   // Draw a cell array.
   // x1,y1        : left down corner
   // x2,y2        : right up corner
   // nx,ny        : array size
   // ic           : array
   //
   // Draw a cell array. The drawing is done with the pixel presicion
   // if (X2-X1)/NX (or Y) is not a exact pixel number the position of
   // the top rigth corner may be wrong.

   int i, j, icol, ix, iy, w, h, current_icol;

   if (!fWindows) return;

   current_icol = -1;
   w = TMath::Max((x2 - x1) / (nx), 1);
   h = TMath::Max((y1 - y2) / (ny), 1);
   ix = x1;

   if (fFillStyleModified) UpdateFillStyle();
   if (fFillColorModified) UpdateFillColor();

   for (i = 0; i < nx; i++) {
      iy = y1 - h;
      for (j = 0; j < ny; j++) {
         icol = ic[i + (nx * j)];
         if (icol != current_icol) {
            gdk_gc_set_foreground(gGCfill, (GdkColor *) & GetColor(icol).color);
            current_icol = icol;
         }

         gdk_win32_draw_rectangle(gCws->drawing, gGCfill, kTRUE, ix,  iy, w, h);
         iy = iy - h;
      }
      ix = ix + w;
   }
}

//______________________________________________________________________________
void TGWin32::DrawFillArea(int n, TPoint *xyt)
{
   // Fill area described by polygon.
   // n         : number of points
   // xy(2,n)   : list of points

   int i;
   static int lastn = 0;
   static GdkPoint *xy = 0;

   if (!fWindows) return;

   if (fFillStyleModified) UpdateFillStyle();
   if (fFillColorModified) UpdateFillColor();

   if (lastn!=n) {
      delete [] (GdkPoint *)xy;
      xy = new GdkPoint[n];
      lastn = n;
   }
   for (i = 0; i < n; i++) {
      xy[i].x = xyt[i].fX;
      xy[i].y = xyt[i].fY;
   }

   if (gFillHollow) {
      gdk_win32_draw_lines(gCws->drawing, gGCfill, xy, n);
   } else {
      gdk_win32_draw_polygon(gCws->drawing, gGCfill, 1, xy, n);
   }
}

//______________________________________________________________________________
void TGWin32::DrawLine(int x1, int y1, int x2, int y2)
{
   // Draw a line.
   // x1,y1        : begin of line
   // x2,y2        : end of line

   if (!fWindows) return;

   if (fLineColorModified) UpdateLineColor();
   if (fPenModified) UpdateLineStyle();

   if (gLineStyle == GDK_LINE_SOLID) {
      gdk_draw_line(gCws->drawing, gGCline, x1, y1, x2, y2);
   } else {
      int i;
      gint8 dashes[32];
      for (i = 0; i < gDashSize; i++) {
         dashes[i] = (gint8) gDashList[i];
      }
      for (i = gDashSize; i < 32; i++) {
         dashes[i] = (gint8) 0;
      }
      gdk_gc_set_dashes(gGCdash, gDashOffset, dashes, gDashSize);
      gdk_draw_line(gCws->drawing, gGCdash, x1, y1, x2, y2);
   }
}

//______________________________________________________________________________
void TGWin32::DrawPolyLine(int n, TPoint * xyt)
{
   // Draw a line through all points.
   // n         : number of points
   // xy        : list of points

   int i;

   if (!fWindows) return;

   Point_t *xy = new Point_t[n];

   for (i = 0; i < n; i++) {
      xy[i].fX = xyt[i].fX;
      xy[i].fY = xyt[i].fY;
   }

   if (fLineColorModified) UpdateLineColor();
   if (fPenModified) UpdateLineStyle();

   if (n > 1) {
      if (gLineStyle == GDK_LINE_SOLID) {
         gdk_win32_draw_lines(gCws->drawing, gGCline, (GdkPoint *)xy, n);
      } else {
         int i;
         gint8 dashes[32];

         for (i = 0; i < gDashSize; i++) {
            dashes[i] = (gint8) gDashList[i];
         }
         for (i = gDashSize; i < 32; i++) {
            dashes[i] = (gint8) 0;
         }

         gdk_gc_set_dashes(gGCdash, gDashOffset, dashes, gDashSize);
         gdk_win32_draw_lines(gCws->drawing, (GdkGC*)gGCdash, (GdkPoint *)xy, n);

         // calculate length of line to update dash offset
         for (i = 1; i < n; i++) {
            int dx = xy[i].fX - xy[i - 1].fX;
            int dy = xy[i].fY - xy[i - 1].fY;

            if (dx < 0) dx = -dx;
            if (dy < 0) dy = -dy;
            gDashOffset += dx > dy ? dx : dy;
         }
         gDashOffset %= gDashLength;
      }
   } else {
      gdk_win32_draw_points( gCws->drawing, gLineStyle == GDK_LINE_SOLID ?
                              gGCline : gGCdash, (GdkPoint *)xy,1);
   }
   delete [] xy;
}

//______________________________________________________________________________
void TGWin32::DrawPolyMarker(int n, TPoint *xyt)
{
   // Draw n markers with the current attributes at position x, y.
   // n    : number of markers to draw
   // xy   : x,y coordinates of markers

   int i;
   static int lastn = 0;
   static GdkPoint *xy = 0;

   if (!fWindows) return;

   if (fMarkerStyleModified) UpdateMarkerStyle();
   if (fMarkerColorModified) UpdateMarkerColor();

   if (lastn!=n) {
      delete [] (GdkPoint *)xy;
      xy = new GdkPoint[n];
      lastn = n;
   }

   for (i = 0; i < n; i++) {
      xy[i].x = xyt[i].fX;
      xy[i].y = xyt[i].fY;
   }

   if (gMarker.n <= 0) {
       gdk_win32_draw_points(gCws->drawing, gGCmark, xy, n);
   } else {
      int r = gMarker.n / 2;
      int m;

      for (m = 0; m < n; m++) {
         int hollow = 0;
         switch (gMarker.type) {
            int i;

         case 0:               // hollow circle
            gdk_win32_draw_arc(gCws->drawing, gGCmark, kFALSE, xy[m].x-r, xy[m].y-r,
                              gMarker.n, gMarker.n, 0, 23040);
            break;

         case 1:               // filled circle
            gdk_win32_draw_arc(gCws->drawing, gGCmark, kTRUE, xy[m].x-r, xy[m].y-r,
                              gMarker.n, gMarker.n, 0, 23040);
            break;

         case 2:               // hollow polygon
            hollow = 1;
         case 3:               // filled polygon
            for (i = 0; i < gMarker.n; i++) {
               gMarker.xy[i].x += xy[m].x;
               gMarker.xy[i].y += xy[m].y;
            }
            if (hollow) {
               gdk_win32_draw_lines(gCws->drawing, gGCmark, (GdkPoint *)gMarker.xy, gMarker.n);
            } else {
               gdk_win32_draw_polygon(gCws->drawing, gGCmark, 1, (GdkPoint *)gMarker.xy, gMarker.n);
            }
            for (i = 0; i < gMarker.n; i++) {
               gMarker.xy[i].x -= xy[m].x;
               gMarker.xy[i].y -= xy[m].y;
            }
            break;

         case 4:               // segmented line
            for (i = 0; i < gMarker.n; i += 2) {
               gdk_draw_line(gCws->drawing, gGCmark,
                             xy[m].x + gMarker.xy[i].x,
                             xy[m].y + gMarker.xy[i].y,
                             xy[m].x + gMarker.xy[i + 1].x,
                             xy[m].y + gMarker.xy[i + 1].y);
            }
            break;
         }
      }
   }
}

//______________________________________________________________________________
void TGWin32::GetCharacterUp(Float_t & chupx, Float_t & chupy)
{
   // Return character up vector.

   chupx = fCharacterUpX;
   chupy = fCharacterUpY;
}

//______________________________________________________________________________
XColor_t &TGWin32::GetColor(Int_t cid)
{
   // Return reference to internal color structure associated
   // to color index cid.

   XColor_t *col = (XColor_t*) fColors->GetValue(cid);
   if (!col) {
      col = new XColor_t;
      fColors->Add(cid, (Long_t) col);
   }
   return *col;
}

//______________________________________________________________________________
Window_t TGWin32::GetCurrentWindow() const
{
   // Return current window pointer. Protected method used by TGWin32TTF.

   return (Window_t)(gCws ? gCws->drawing : 0);
}

//______________________________________________________________________________
GdkGC *TGWin32::GetGC(Int_t which) const
{
   // Return desired Graphics Context ("which" maps directly on gGCList[]).
   // Protected method used by TGWin32TTF.

   if (which >= kMAXGC || which < 0) {
      Error("GetGC", "trying to get illegal GdkGC (which = %d)", which);
      return 0;
   }

   return gGClist[which];
}

//______________________________________________________________________________
Int_t TGWin32::GetDoubleBuffer(int wid)
{
   // Query the double buffer value for the window wid.

   if (!fWindows) return 0;

   gTws = &fWindows[wid];

   if (!gTws->open) {
      return -1;
   } else {
      return gTws->double_buffer;
   }
}

//______________________________________________________________________________
void TGWin32::GetGeometry(int wid, int &x, int &y, unsigned int &w,
                          unsigned int &h)
{
   // Return position and size of window wid.
   // wid        : window identifier
   // x,y        : window position (output)
   // w,h        : window size (output)
   // if wid < 0 the size of the display is returned

   if (!fWindows) return;

   if (wid < 0) {
      x = 0;
      y = 0;

      w = gdk_screen_width();
      h = gdk_screen_height();
   } else {
      int depth;
      int width, height;

      gTws = &fWindows[wid];
      gdk_window_get_geometry((GdkDrawable *) gTws->window, &x, &y,
                              &width, &height, &depth);

      gdk_window_get_deskrelative_origin((GdkDrawable *) gTws->window, &x, &y);

      if (width > 0 && height > 0) {
         gTws->width = width;
         gTws->height = height;
      }
      w = gTws->width;
      h = gTws->height;
   }
}

//______________________________________________________________________________
const char *TGWin32::DisplayName(const char *dpyName)
{
   // Return hostname on which the display is opened.

   return "localhost";          //return gdk_get_display();
}

//______________________________________________________________________________
void TGWin32::GetPlanes(int &nplanes)
{
   // Get maximum number of planes.

   nplanes = gdk_visual_get_best_depth();
}

//______________________________________________________________________________
void TGWin32::GetRGB(int index, float &r, float &g, float &b)
{
   // Get rgb values for color "index".

   if (index == 0) {
      r = g = b = 1.0;
   } else if (index == 1) {
      r = g = b = 0.0;
   } else {
      XColor_t &col = GetColor(index);
      r = ((float) col.color.red) / ((float) kBIGGEST_RGB_VALUE);
      g = ((float) col.color.green) / ((float) kBIGGEST_RGB_VALUE);
      b = ((float) col.color.blue) / ((float) kBIGGEST_RGB_VALUE);
   }
}

//______________________________________________________________________________
void TGWin32::GetTextExtent(unsigned int &w, unsigned int &h, char *mess)
{
   // Return the size of a character string.
   // iw          : text width
   // ih          : text height
   // mess        : message

   TTF::SetTextFont(gTextFont);
   TTF::SetTextSize(fTextSize);
   TTF::GetTextExtent(w, h, mess);
}

//______________________________________________________________________________
Window_t TGWin32::GetWindowID(int wid)
{
   // Return the X11 window identifier.
   // wid      : Workstation identifier (input)

   if (!fWindows) return 0;
   return (Window_t) fWindows[wid].window;
}

//______________________________________________________________________________
void TGWin32::MoveWindow(int wid, int x, int y)
{
   // Move the window wid.
   // wid  : GdkWindow identifier.
   // x    : x new window position
   // y    : y new window position

   if (!fWindows) return;

   gTws = &fWindows[wid];
   if (!gTws->open) return;

   gdk_window_move((GdkDrawable *) gTws->window, x, y);
}

//______________________________________________________________________________
Int_t TGWin32::OpenPixmap(unsigned int w, unsigned int h)
{
   // Open a new pixmap.
   // w,h : Width and height of the pixmap.

   int i, wid;
   int ww, hh, depth;
   int wval = w;
   int hval = h;

   // Select next free window number
 again:
   for (wid = 0; wid < fMaxNumberOfWindows; wid++) {
      if (!fWindows[wid].open) {
         fWindows[wid].open = 1;
         gCws = &fWindows[wid];
         break;
      }
   }
   if (wid == fMaxNumberOfWindows) {
      int newsize = fMaxNumberOfWindows + 10;
      fWindows = (XWindow_t *) TStorage::ReAlloc(fWindows,
                                                 newsize * sizeof(XWindow_t),
                                                 fMaxNumberOfWindows *
                                                 sizeof(XWindow_t));

      for (i = fMaxNumberOfWindows; i < newsize; i++) fWindows[i].open = 0;
      fMaxNumberOfWindows = newsize;
      goto again;
   }

   depth =gdk_visual_get_best_depth();
   gCws->window = (GdkPixmap *) gdk_pixmap_new(GDK_ROOT_PARENT(),wval,hval,depth);
   gdk_drawable_get_size((GdkDrawable *) gCws->window, &ww, &hh);

   for (i = 0; i < kMAXGC; i++) {
      gdk_gc_set_clip_mask((GdkGC *) gGClist[i], (GdkDrawable *)None);
   }

   SetColor(gGCpxmp, 0);
   gdk_win32_draw_rectangle(gCws->window,(GdkGC *)gGCpxmp, kTRUE,
                           0, 0, ww, hh);
   SetColor(gGCpxmp, 1);

   // Initialise the window structure
   gCws->drawing = gCws->window;
   gCws->buffer = 0;
   gCws->double_buffer = 0;
   gCws->ispixmap = 1;
   gCws->clip = 0;
   gCws->width = wval;
   gCws->height = hval;
   gCws->new_colors = 0;

   return wid;
}

//______________________________________________________________________________
Int_t TGWin32::InitWindow(ULong_t win)
{
   // Open window and return window number.
   // Return -1 if window initialization fails.

   GdkWindowAttr attributes;
   unsigned long attr_mask = 0;
   int wid, xval, yval;
   int wval, hval, depth;

   GdkWindow *wind = (GdkWindow *) win;

   gdk_window_get_geometry(wind, &xval, &yval, &wval, &hval, &depth);

   // Select next free window number

 again:
   for (wid = 0; wid < fMaxNumberOfWindows; wid++) {
      if (!fWindows[wid].open) {
         fWindows[wid].open = 1;
         fWindows[wid].double_buffer = 0;
         gCws = &fWindows[wid];
         break;
      }
   }

   if (wid == fMaxNumberOfWindows) {
      int newsize = fMaxNumberOfWindows + 10;
      fWindows =
          (XWindow_t *) TStorage::ReAlloc(fWindows,
                                          newsize * sizeof(XWindow_t),
                                          fMaxNumberOfWindows *
                                          sizeof(XWindow_t));

      for (int i = fMaxNumberOfWindows; i < newsize; i++) {
         fWindows[i].open = 0;
      }

      fMaxNumberOfWindows = newsize;
      goto again;
   }
   // Create window
   attributes.wclass = GDK_INPUT_OUTPUT;
   attributes.event_mask = 0L;  //GDK_ALL_EVENTS_MASK;
   attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK |
       GDK_PROPERTY_CHANGE_MASK;
//                            GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK;
   if (xval >= 0) {
      attributes.x = xval;
   } else {
      attributes.x = -1.0 * xval;
   }

   if (yval >= 0) {
      attributes.y = yval;
   } else {
      attributes.y = -1.0 * yval;
   }
   attributes.width = wval;
   attributes.height = hval;
   attributes.colormap = gdk_colormap_get_system();
   attributes.visual = gdk_window_get_visual(wind);
   attributes.override_redirect = TRUE;

   if ((attributes.y > 0) && (attributes.x > 0)) {
      attr_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_COLORMAP |
          GDK_WA_WMCLASS | GDK_WA_NOREDIR;
   } else {
      attr_mask = GDK_WA_COLORMAP | GDK_WA_WMCLASS | GDK_WA_NOREDIR;
   }

   if (attributes.visual != NULL) {
      attr_mask |= GDK_WA_VISUAL;
   }
   attributes.window_type = GDK_WINDOW_CHILD;
   gCws->window = gdk_window_new(wind, &attributes, attr_mask);
   HWND window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)gCws->window);
   ::ShowWindow(window, SW_SHOWNORMAL);
   ::ShowWindow(window, SW_RESTORE);
   ::BringWindowToTop(window);

   if (!fUseSysPointers) {
      ::SetClassLong(window, GCL_HCURSOR,
                    (LONG)GDK_CURSOR_XID(fCursors[kPointer]));
   }
   
   // Initialise the window structure

   gCws->drawing = gCws->window;
   gCws->buffer = 0;
   gCws->double_buffer = 0;
   gCws->ispixmap = 0;
   gCws->clip = 0;
   gCws->width = wval;
   gCws->height = hval;
   gCws->new_colors = 0;

   return wid;
}

//______________________________________________________________________________
void TGWin32::QueryPointer(int &ix, int &iy)
{
   // Query pointer position.
   // ix       : X coordinate of pointer
   // iy       : Y coordinate of pointer
   // (both coordinates are relative to the origin of the root window)

   //GdkModifierType mask;
   //GdkWindow *retw = gdk_window_get_pointer((GdkWindow *) gCws->window,
   //                                          &ix, &iy, &mask);
   POINT cpt;
   GetCursorPos(&cpt);
   ix = cpt.x;
   iy = cpt.y;
}

//______________________________________________________________________________
void TGWin32::RemovePixmap(GdkDrawable *pix)
{
   // Remove the pixmap pix.

   gdk_pixmap_unref((GdkPixmap *)pix);
}

//______________________________________________________________________________
Int_t TGWin32::RequestLocator(Int_t mode, Int_t ctyp, Int_t & x, Int_t & y)
{
   // Request Locator position.
   // x,y       : cursor position at moment of button press (output)
   // ctyp      : cursor type (input)
   //   ctyp=1 tracking cross
   //   ctyp=2 cross-hair
   //   ctyp=3 rubber circle
   //   ctyp=4 rubber band
   //   ctyp=5 rubber rectangle
   //
   // mode      : input mode
   //   mode=0 request
   //   mode=1 sample
   //
   // Request locator:
   // return button number  1 = left is pressed
   //                       2 = middle is pressed
   //                       3 = right is pressed
   //        in sample mode:
   //                      11 = left is released
   //                      12 = middle is released
   //                      13 = right is released
   //                      -1 = nothing is pressed or released
   //                      -2 = leave the window
   //                    else = keycode (keyboard is pressed)

   static int xloc = 0;
   static int yloc = 0;
   static int xlocp = 0;
   static int ylocp = 0;
   static GdkCursor *cursor = NULL;
   Int_t  xtmp, ytmp;

   GdkEvent *event;
   int button_press;
   int radius;

   // Change the cursor shape
   if (cursor == NULL) {
      if (ctyp > 1) {
         gdk_window_set_cursor((GdkWindow *)gCws->window, (GdkCursor *)gNullCursor);
         gdk_gc_set_foreground((GdkGC *) gGCecho, &GetColor(0).color);
      } else {
         if (fUseSysPointers)
            cursor = gdk_syscursor_new((ULong_t)IDC_CROSS);
         else
            cursor = gdk_cursor_new((GdkCursorType)GDK_CROSSHAIR);
         gdk_window_set_cursor((GdkWindow *)gCws->window, (GdkCursor *)cursor);
      }
   }

   // Event loop
   button_press = 0;

   // Set max response time to 2 minutes to avoid timeout
   // in TGWin32ProxyBase::ForwardCallBack during RequestLocator
   TGWin32VirtualXProxy::fMaxResponseTime = 120000;
   while (button_press == 0) {
      event = gdk_event_get();

      switch (ctyp) {

      case 1:
         break;

      case 2:
         gdk_draw_line(gCws->window, gGCecho, xloc, 0, xloc, gCws->height);
         gdk_draw_line(gCws->window, gGCecho, 0, yloc, gCws->width, yloc);
         break;

      case 3:
         radius = (int) TMath::Sqrt((double)((xloc - xlocp) * (xloc - xlocp) +
                                             (yloc - ylocp) * (yloc - ylocp)));

         gdk_win32_draw_arc(gCws->window, gGCecho, kFALSE,
                            xlocp - radius, ylocp - radius,
                            2 * radius, 2 * radius, 0, 23040);
         break;

      case 4:
         gdk_draw_line(gCws->window, gGCecho, xlocp, ylocp, xloc, yloc);
         break;

      case 5:
         gdk_win32_draw_rectangle( gCws->window, gGCecho, kFALSE,
                                 TMath::Min(xlocp, xloc), TMath::Min(ylocp, yloc),
                                 TMath::Abs(xloc - xlocp), TMath::Abs(yloc - ylocp));
         break;

      default:
         break;
      }

      xloc = event->button.x;
      yloc = event->button.y;

      switch (event->type) {

      case GDK_LEAVE_NOTIFY:
         if (mode == 0) {
            while (1) {
               event = gdk_event_get();

               if (event->type == GDK_ENTER_NOTIFY) {
                  gdk_event_free(event);
                  break;
               }
               gdk_event_free(event);
            }
         } else {
            button_press = -2;
         }
         break;

      case GDK_BUTTON_PRESS:
         button_press = event->button.button;
         xlocp = event->button.x;
         ylocp = event->button.y;
         gdk_cursor_unref(cursor);
         cursor = 0;
         break;

      case GDK_BUTTON_RELEASE:
         if (mode == 1) {
            button_press = 10 + event->button.button;
            xlocp = event->button.x;
            ylocp = event->button.y;
         }
         break;

      case GDK_KEY_PRESS:
         if (mode == 1) {
            button_press = event->key.keyval;
            xlocp = event->button.x;
            ylocp = event->button.y;
         }
         break;

      case GDK_KEY_RELEASE:
         if (mode == 1) {
            button_press = -1 * (int)(event->key.keyval);
            xlocp = event->button.x;
            ylocp = event->button.y;
         }
         break;

      default:
         break;
      }

      xtmp = event->button.x;
      ytmp = event->button.y;

      gdk_event_free(event);

      if (mode == 1) {
         if (button_press == 0) {
            button_press = -1;
         }
         break;
      }
   }
   TGWin32VirtualXProxy::fMaxResponseTime = 1000;

   x = xtmp;
   y = ytmp;

   return button_press;
}

//______________________________________________________________________________
Int_t TGWin32::RequestString(int x, int y, char *text)
{
   // Request a string.
   // x,y         : position where text is displayed
   // text        : text displayed (input), edited text (output)
   //
   // Request string:
   // text is displayed and can be edited with Emacs-like keybinding
   // return termination code (0 for ESC, 1 for RETURN)

   static GdkCursor *cursor = NULL;
   static int percent = 0;      // bell volume
   static GdkWindow *CurWnd;
   HWND focuswindow;
   GdkEvent *event;
   KeySym keysym;
   int key = -1;
   int len_text = strlen(text);
   int nt;                      // defined length of text
   int pt;                      // cursor position in text

   CurWnd = (GdkWindow *)gCws->window;
   // change the cursor shape
   if (cursor == NULL) {
      if (fUseSysPointers)
         cursor = gdk_syscursor_new((ULong_t)IDC_HELP);
      else
         cursor = gdk_cursor_new((GdkCursorType)GDK_QUESTION_ARROW);
   }
   if (cursor != 0) {
      gdk_window_set_cursor(CurWnd, cursor);
   }
   for (nt = len_text; nt > 0 && text[nt - 1] == ' '; nt--);

   pt = nt;
   focuswindow = ::SetFocus((HWND)GDK_DRAWABLE_XID(CurWnd));

   // Set max response time to 2 minutes to avoid timeout
   // in TGWin32ProxyBase::ForwardCallBack during RequestString
   TGWin32VirtualXProxy::fMaxResponseTime = 120000;
   TTF::SetTextFont(gTextFont);
   TTF::SetTextSize(fTextSize);
   do {
      char tmp[2];
      char keybuf[8];
      char nbytes;
      UInt_t dx, ddx, h;
      int i;

      if (EventsPending()) {
         event = gdk_event_get();
      } else {
         gSystem->ProcessEvents();
         ::SleepEx(10, kTRUE);
         continue;
      }

      DrawText(x, y, 0.0, 1.0, text, kOpaque);
      TTF::GetTextExtent(dx, h, text);
      DrawText(x+dx, y, 0.0, 1.0, " ", kOpaque);

      if (pt == 0) {
         dx = 0;
      } else {
         char *stmp = new char[pt+1];
         strncpy(stmp, text, pt);
         stmp[pt] = '\0';
         TTF::GetTextExtent(ddx, h, stmp);
         dx = ddx;
         delete[] stmp;
      }

      if (pt < len_text) {
         tmp[0] = text[pt];
         tmp[1] = '\0';
         DrawText(x+dx, y, 0.0, 1.0, tmp, kOpaque);
      } else {
         DrawText(x+dx, y, 0.0, 1.0, " ", kOpaque);
      }

      if (event != NULL) {
         switch (event->type) {
         case GDK_BUTTON_PRESS:
         case GDK_ENTER_NOTIFY:
            focuswindow = ::SetFocus((HWND)GDK_DRAWABLE_XID(CurWnd));
            break;

         case GDK_LEAVE_NOTIFY:
            ::SetFocus(focuswindow);
            break;
         case GDK_KEY_PRESS:
            nbytes = event->key.length;
            for (i = 0; i < nbytes; i++) {
               keybuf[i] = event->key.string[i];
            }
            keysym = event->key.keyval;
            switch (keysym) {   // map cursor keys
            case GDK_BackSpace:
               keybuf[0] = 0x08;	// backspace
               nbytes = 1;
               break;
            case GDK_Return:
               keybuf[0] = 0x0d;	// return
               nbytes = 1;
               break;
            case GDK_Delete:
               keybuf[0] = 0x7f;	// del
               nbytes = 1;
               break;
            case GDK_Escape:
               keybuf[0] = 0x1b;	// esc
               nbytes = 1;
               break;
            case GDK_Home:
               keybuf[0] = 0x01;	// home
               nbytes = 1;
               break;
            case GDK_Left:
               keybuf[0] = 0x02;	// backward
               nbytes = 1;
               break;
            case GDK_Right:
               keybuf[0] = 0x06;	// forward
               nbytes = 1;
               break;
            case GDK_End:
               keybuf[0] = 0x05;	// end
               nbytes = 1;
               break;
            }
            if (nbytes == 1) {
               if (isascii(keybuf[0]) && isprint(keybuf[0])) {
                  // insert character
                  if (nt < len_text) {
                     nt++;
                  }
                  for (i = nt - 1; i > pt; i--) {
                     text[i] = text[i - 1];
                  }
                  if (pt < len_text) {
                     text[pt] = keybuf[0];
                     pt++;
                  }
               } else {
                  switch (keybuf[0]) {
                     // Emacs-like editing keys

                  case 0x08:   //'\010':    // backspace
                  case 0x7f:   //'\177':    // delete
                     // delete backward
                     if (pt > 0) {
                        for (i = pt; i < nt; i++) {
                           text[i - 1] = text[i];
                        }
                        text[nt - 1] = ' ';
                        nt--;
                        pt--;
                     }
                     break;
                  case 0x01:   //'\001':    // ^A
                     // beginning of line
                     pt = 0;
                     break;
                  case 0x02:   //'\002':    // ^B
                     // move backward
                     if (pt > 0) {
                        pt--;
                     }
                     break;
                  case 0x04:   //'\004':    // ^D
                     // delete forward
                     if (pt > 0) {
                        for (i = pt; i < nt; i++) {
                           text[i - 1] = text[i];
                        }
                        text[nt - 1] = ' ';
                        pt--;
                     }
                     break;
                  case 0x05:   //'\005':    // ^E
                     // end of line
                     pt = nt;
                     break;

                  case 0x06:   //'\006':    // ^F
                     // move forward
                     if (pt < nt) {
                        pt++;
                     }
                     break;
                  case 0x0b:   //'\013':    // ^K
                     // delete to end of line
                     for (i = pt; i < nt; i++)
                        text[i] = ' ';
                     nt = pt;
                     break;
                  case 0x14:   //'\024':    // ^T
                     // transpose
                     if (pt > 0) {
                        char c = text[pt];
                        text[pt] = text[pt - 1];
                        text[pt - 1] = c;
                     }
                     break;
                  case 0x0A:   //'\012':    // newline
                  case 0x0D:   //'\015':    // return
                     key = 1;
                     break;
                  case 0x1B:   //'\033':    // escape
                     key = 0;
                     break;

                  default:
                     gSystem->Beep();
                     break;
                  }
               }
            }
         default:
            SetInputFocus((Window_t)gCws->window);
            break;
         }
         gdk_event_free(event);
      }
   } while (key < 0);
   TGWin32VirtualXProxy::fMaxResponseTime = 1000;
   ::SetFocus(focuswindow);
   SetInputFocus((Window_t)CurWnd);

   gdk_window_set_cursor(CurWnd, (GdkCursor *)fCursors[kPointer]);
   if (cursor != 0) {
      gdk_cursor_unref(cursor);
      cursor = 0;
   }

   return key;
}

//______________________________________________________________________________
void TGWin32::RescaleWindow(int wid, unsigned int w, unsigned int h)
{
   // Rescale the window wid.
   // wid  : GdkWindow identifier
   // w    : Width
   // h    : Heigth

    int i;

   if (!fWindows) return;

   gTws = &fWindows[wid];
   if (!gTws->open)
      return;

   // don't do anything when size did not change
   if (gTws->width == w && gTws->height == h)
      return;

   gdk_window_resize((GdkWindow *) gTws->window, w, h);

   if (gTws->buffer) {
      // don't free and recreate pixmap when new pixmap is smaller
      if (gTws->width < w || gTws->height < h) {
         gdk_pixmap_unref(gTws->buffer);
         gTws->buffer = gdk_pixmap_new(GDK_ROOT_PARENT(),	// NULL,
                                       w, h, gdk_visual_get_best_depth());
      }
      for (i = 0; i < kMAXGC; i++) {
         gdk_gc_set_clip_mask(gGClist[i], None);
      }
      SetColor(gGCpxmp, 0);
      gdk_win32_draw_rectangle(gTws->buffer, gGCpxmp, 1, 0, 0, w, h);
      SetColor(gGCpxmp, 1);

      if (gTws->double_buffer) gTws->drawing = gTws->buffer;
   }
   gTws->width = w;
   gTws->height = h;
}

//______________________________________________________________________________
int TGWin32::ResizePixmap(int wid, unsigned int w, unsigned int h)
{
   // Resize a pixmap.
   // wid : pixmap to be resized
   // w,h : Width and height of the pixmap

   int i, ww, hh, depth;
   int wval = w;
   int hval = h;

   if (!fWindows) return 0;

   gTws = &fWindows[wid];

   // don't do anything when size did not change
   //  if (gTws->width == wval && gTws->height == hval) return 0;

   // due to round-off errors in TPad::Resize() we might get +/- 1 pixel
   // change, in those cases don't resize pixmap
   if (gTws->width >= wval - 1 && gTws->width <= wval + 1 &&
       gTws->height >= hval - 1 && gTws->height <= hval + 1)
      return 0;

   // don't free and recreate pixmap when new pixmap is smaller
   if (gTws->width < wval || gTws->height < hval) {
      gdk_pixmap_unref((GdkPixmap *)gTws->window);
      depth = gdk_visual_get_best_depth();
      gTws->window = gdk_pixmap_new(GDK_ROOT_PARENT(), wval, hval, depth);
   }

   gdk_drawable_get_size(gTws->window, &ww, &hh);

   for (i = 0; i < kMAXGC; i++) {
      gdk_gc_set_clip_mask((GdkGC *) gGClist[i], (GdkDrawable *)None);
   }

   SetColor(gGCpxmp, 0);
   gdk_win32_draw_rectangle(gTws->window,(GdkGC *)gGCpxmp, kTRUE, 0, 0, ww, hh);
   SetColor(gGCpxmp, 1);

   // Initialise the window structure
   gTws->drawing = gTws->window;
   gTws->width = wval;
   gTws->height = hval;
   return 1;
}

//______________________________________________________________________________
void TGWin32::ResizeWindow(int wid)
{
   // Resize the current window if necessary.

   int i;
   int xval = 0, yval = 0;
   GdkWindow *win, *root = NULL;
   int wval = 0, hval = 0, depth = 0;

   if (!fWindows) return;

   gTws = &fWindows[wid];

   win = (GdkWindow *) gTws->window;
   gdk_window_get_geometry(win, &xval, &yval,
                           &wval, &hval, &depth);

   // don't do anything when size did not change
   if (gTws->width == wval && gTws->height == hval) {
      return;
   }

   gdk_window_resize((GdkWindow *) gTws->window, wval, hval);

   if (gTws->buffer) {
      if (gTws->width < wval || gTws->height < hval) {
         gdk_pixmap_unref((GdkPixmap *)gTws->buffer);
         depth = gdk_visual_get_best_depth();
         gTws->buffer = (GdkPixmap *) gdk_pixmap_new(GDK_ROOT_PARENT(),
                                                     wval, hval, depth);
      }

      for (i = 0; i < kMAXGC; i++) {
         gdk_gc_set_clip_mask((GdkGC *) gGClist[i], (GdkDrawable *)None);
      }

      SetColor(gGCpxmp, 0);
      gdk_win32_draw_rectangle(gTws->buffer,(GdkGC *)gGCpxmp, kTRUE, 0, 0, wval, hval);

      SetColor(gGCpxmp, 1);

      if (gTws->double_buffer) gTws->drawing = gTws->buffer;
   }

   gTws->width = wval;
   gTws->height = hval;
}

//______________________________________________________________________________
void TGWin32::SelectWindow(int wid)
{
   // Select window to which subsequent output is directed.

   int i;
   GdkRectangle rect;

   if (!fWindows || wid < 0 || wid >= fMaxNumberOfWindows || !fWindows[wid].open) {
      return;
   }

   gCws = &fWindows[wid];

   if (gCws->clip && !gCws->ispixmap && !gCws->double_buffer) {
      rect.x = gCws->xclip;
      rect.y = gCws->yclip;
      rect.width = gCws->wclip;
      rect.height = gCws->hclip;

      for (i = 0; i < kMAXGC; i++) {
         gdk_gc_set_clip_rectangle((GdkGC *) gGClist[i], &rect);
      }
   } else {
      for (i = 0; i < kMAXGC; i++) {
         gdk_gc_set_clip_mask((GdkGC *) gGClist[i], (GdkDrawable *)None);
      }
   }
}

//______________________________________________________________________________
void TGWin32::SetCharacterUp(Float_t chupx, Float_t chupy)
{
   // Set character up vector.

   if (chupx == fCharacterUpX && chupy == fCharacterUpY) return;

   if (chupx == 0 && chupy == 0) {
      fTextAngle = 0;
   } else if (chupx == 0 && chupy == 1) {
      fTextAngle = 0;
   } else if (chupx == -1 && chupy == 0) {
      fTextAngle = 90;
   } else if (chupx == 0 && chupy == -1) {
      fTextAngle = 180;
   } else if (chupx == 1 && chupy == 0) {
      fTextAngle = 270;
   } else {
      fTextAngle =
          ((TMath::
            ACos(chupx / TMath::Sqrt(chupx * chupx + chupy * chupy)) *
            180.) / 3.14159) - 90;
      if (chupy < 0) fTextAngle = 180 - fTextAngle;
      if (TMath::Abs(fTextAngle) <= 0.01) fTextAngle = 0;
   }
   fCharacterUpX = chupx;
   fCharacterUpY = chupy;
}

//______________________________________________________________________________
void TGWin32::SetClipOFF(int wid)
{
   // Turn off the clipping for the window wid.

   if (!fWindows) return;

   gTws = &fWindows[wid];
   gTws->clip = 0;

   for (int i = 0; i < kMAXGC; i++) {
      gdk_gc_set_clip_mask((GdkGC *) gGClist[i], (GdkDrawable *)None);
   }
}

//______________________________________________________________________________
void TGWin32::SetClipRegion(int wid, int x, int y, unsigned int w,
                            unsigned int h)
{
   // Set clipping region for the window wid.
   // wid        : GdkWindow indentifier
   // x,y        : origin of clipping rectangle
   // w,h        : size of clipping rectangle;

   if (!fWindows) return;

   gTws = &fWindows[wid];
   gTws->xclip = x;
   gTws->yclip = y;
   gTws->wclip = w;
   gTws->hclip = h;
   gTws->clip = 1;
   GdkRectangle rect;

   if (gTws->clip && !gTws->ispixmap && !gTws->double_buffer) {
      rect.x = gTws->xclip;
      rect.y = gTws->yclip;
      rect.width = gTws->wclip;
      rect.height = gTws->hclip;

      for (int i = 0; i < kMAXGC; i++) {
         gdk_gc_set_clip_rectangle((GdkGC *)gGClist[i], &rect);
      }
   }
}

//______________________________________________________________________________
ULong_t TGWin32::GetPixel(Color_t ci)
{
   // Return pixel value associated to specified ROOT color number.

   TColor *color = gROOT->GetColor(ci);
   if (color)
      SetRGB(ci, color->GetRed(), color->GetGreen(), color->GetBlue());
   XColor_t &col = GetColor(ci);
   return col.color.pixel;
}

//______________________________________________________________________________
void TGWin32::SetColor(GdkGC *gc, int ci)
{
   // Set the foreground color in GdkGC.

   GdkGCValues gcvals;
   GdkColor color;

   if (ci<=0) ci = 10; //white

   TColor *clr = gROOT->GetColor(ci);
   if (clr)
      SetRGB(ci, clr->GetRed(), clr->GetGreen(), clr->GetBlue());

   XColor_t &col = GetColor(ci);
   if (fColormap && !col.fDefined) {
      col = GetColor(0);
   } else if (!fColormap && (ci < 0 || ci > 1)) {
      col = GetColor(0);
   }

   if (fDrawMode == kXor) {
      gdk_gc_get_values(gc, &gcvals);

      color.pixel = col.color.pixel ^ gcvals.background.pixel;
      color.red = GetRValue(color.pixel);
      color.green = GetGValue(color.pixel);
      color.blue = GetBValue(color.pixel);
      gdk_gc_set_foreground(gc, &color);

   } else {
      gdk_gc_set_foreground(gc, &col.color);

      // make sure that foreground and background are different
      gdk_gc_get_values(gc, &gcvals);

      if (gcvals.foreground.pixel != gcvals.background.pixel) {
         gdk_gc_set_background(gc, &GetColor(!ci).color);
      }
   }
}

//______________________________________________________________________________
void TGWin32::SetCursor(int wid, ECursor cursor)
{
   // Set the cursor.

   if (!fWindows) return;

   gTws = &fWindows[wid];
   gdk_window_set_cursor((GdkWindow *)gTws->window, (GdkCursor *)fCursors[cursor]);
}

//______________________________________________________________________________
void TGWin32::SetCursor(Window_t id, Cursor_t curid)
{
   // Set the specified cursor.

   if (!id) return;

   static GdkWindow *lid = 0;
   static GdkCursor *lcur = 0;

   if ((lid == (GdkWindow *)id) && (lcur==(GdkCursor *)curid)) return;
   lid = (GdkWindow *)id;
   lcur = (GdkCursor *)curid;

   gdk_window_set_cursor((GdkWindow *) id, (GdkCursor *)curid);
}

//______________________________________________________________________________
void TGWin32::SetDoubleBuffer(int wid, int mode)
{
   // Set the double buffer on/off on window wid.
   // wid  : GdkWindow identifier.
   //        999 means all the opened windows.
   // mode : 1 double buffer is on
   //        0 double buffer is off

   if (!fWindows) return;

   if (wid == 999) {
      for (int i = 0; i < fMaxNumberOfWindows; i++) {
         gTws = &fWindows[i];
         if (gTws->open) {
            switch (mode) {
            case 1:
               SetDoubleBufferON();
               break;
            default:
               SetDoubleBufferOFF();
               break;
            }
         }
      }
   } else {
      gTws = &fWindows[wid];
      if (!gTws->open) return;

      switch (mode) {
      case 1:
         SetDoubleBufferON();
         return;
      default:
         SetDoubleBufferOFF();
         return;
      }
   }
}

//______________________________________________________________________________
void TGWin32::SetDoubleBufferOFF()
{
   // Turn double buffer mode off.

   if (!gTws->double_buffer) return;
   gTws->double_buffer = 0;
   gTws->drawing = gTws->window;
}

//______________________________________________________________________________
void TGWin32::SetDoubleBufferON()
{
   // Turn double buffer mode on.

   if (!fWindows || gTws->double_buffer || gTws->ispixmap) return;

   if (!gTws->buffer) {
      gTws->buffer = gdk_pixmap_new(GDK_ROOT_PARENT(),	//NULL,
                                    gTws->width, gTws->height,
                                    gdk_visual_get_best_depth());
      SetColor(gGCpxmp, 0);
      gdk_win32_draw_rectangle(gTws->buffer, gGCpxmp, 1, 0, 0, gTws->width,
                         gTws->height);
      SetColor(gGCpxmp, 1);
   }
   for (int i = 0; i < kMAXGC; i++) {
      gdk_gc_set_clip_mask(gGClist[i], None);
   }
   gTws->double_buffer = 1;
   gTws->drawing = gTws->buffer;
}

//______________________________________________________________________________
void TGWin32::SetDrawMode(EDrawMode mode)
{
   // Set the drawing mode.
   // mode : drawing mode
   //   mode=1 copy
   //   mode=2 xor
   //   mode=3 invert
   //   mode=4 set the suitable mode for cursor echo according to
   //          the vendor

   int i;

   switch (mode) {
   case kCopy:
      for (i = 0; i < kMAXGC; i++) {
         gdk_gc_set_function(gGClist[i], GDK_COPY);
      }
      break;

   case kXor:
      for (i = 0; i < kMAXGC; i++) {
         gdk_gc_set_function(gGClist[i], GDK_XOR);
      }
      break;

   case kInvert:
      for (i = 0; i < kMAXGC; i++) {
         gdk_gc_set_function(gGClist[i], GDK_INVERT);
      }
      break;
   }
   fDrawMode = mode;
}

//______________________________________________________________________________
void TGWin32::SetFillColor(Color_t cindex)
{
   // Set color index for fill areas.

   Int_t indx = Int_t(cindex);

   if (!gStyle->GetFillColor() && cindex > 1) {
      indx = 0;
   }

   fFillColor = indx;
   fFillColorModified = kTRUE;
}

//______________________________________________________________________________
void TGWin32::UpdateFillColor()
{
   //

   if (fFillColor >= 0) {
      SetColor(gGCfill, fFillColor);
   }

   // invalidate fill pattern
   if (gFillPattern != NULL) {
      gdk_pixmap_unref(gFillPattern);
      gFillPattern = NULL;
   }
   fFillColorModified = kFALSE;
}

//______________________________________________________________________________
void TGWin32::SetFillStyle(Style_t fstyle)
{
   // Set fill area style.
   // fstyle   : compound fill area interior style
   //    fstyle = 1000*interiorstyle + styleindex

   if (fFillStyle==fstyle) return;

   fFillStyle = fstyle;
   fFillStyleModified = kTRUE;
}

//______________________________________________________________________________
void TGWin32::UpdateFillStyle()
{
   // Set fill area style index.

   static int current_fasi = 0;

   Int_t style = fFillStyle / 1000;
   Int_t fasi = fFillStyle % 1000;

   switch (style) {

   case 1:                     // solid
      gFillHollow = 0;
      gdk_gc_set_fill(gGCfill, GDK_SOLID);
      break;

   case 2:                     // pattern
      gFillHollow = 1;
      break;

   case 3:                     // hatch
      gFillHollow = 0;
      gdk_gc_set_fill(gGCfill, GDK_STIPPLED);

      if (fasi != current_fasi) {
         if (gFillPattern != NULL) {
            gdk_pixmap_unref(gFillPattern);
            gFillPattern = NULL;
         }
         int stn = (fasi >= 1 && fasi <=25) ? fasi : 2;
         gFillPattern = gdk_bitmap_create_from_data(GDK_ROOT_PARENT(),
                                                    (const char *)gStipples[stn], 16, 16);
         gdk_gc_set_stipple(gGCfill, gFillPattern);
         current_fasi = fasi;
      }
      break;

   default:
      gFillHollow = 1;
   }

   fFillStyleModified = kFALSE;
}

//______________________________________________________________________________
void TGWin32::SetInput(int inp)
{
   // Set input on or off.

   EnableWindow((HWND) GDK_DRAWABLE_XID(gCws->window), inp);
}

//______________________________________________________________________________
void TGWin32::SetLineColor(Color_t cindex)
{
   // Set color index for lines.

   if ((cindex < 0) || (cindex==fLineColor)) return;

   fLineColor =  cindex;
   fLineColorModified = kTRUE;
}

//______________________________________________________________________________
void TGWin32::UpdateLineColor()
{
   //

   SetColor(gGCline, Int_t(fLineColor));
   SetColor(gGCdash, Int_t(fLineColor));
   fLineColorModified = kFALSE;
}

//______________________________________________________________________________
void TGWin32::SetLineType(int n, int *dash)
{
   // Set line type.
   // n         : length of dash list
   // dash(n)   : dash segment lengths
   //
   // if n <= 0 use solid lines
   // if n >  0 use dashed lines described by DASH(N)
   //    e.g. N=4,DASH=(6,3,1,3) gives a dashed-dotted line with dash length 6
   //    and a gap of 7 between dashes

   if (n <= 0) {
      gLineStyle = GDK_LINE_SOLID;
      gdk_gc_set_line_attributes(gGCline, fLineWidth,
                                 (GdkLineStyle)gLineStyle,
                                 (GdkCapStyle) gCapStyle,
                                 (GdkJoinStyle) gJoinStyle);
   } else {
      int i;
      gDashSize = TMath::Min((int)sizeof(gDashList),n);
      gDashLength = 0;
      for (i = 0; i < gDashSize; i++) {
         gDashList[i] = dash[i];
         gDashLength += gDashList[i];
      }
      gDashOffset = 0;
      gLineStyle = GDK_LINE_ON_OFF_DASH;
      gdk_gc_set_line_attributes(gGCdash, fLineWidth,
                                 (GdkLineStyle) gLineStyle,
                                 (GdkCapStyle) gCapStyle,
                                 (GdkJoinStyle) gJoinStyle);
   }
   fPenModified = kFALSE;
}

//______________________________________________________________________________
void TGWin32::SetLineStyle(Style_t lstyle)
{
   // Set line style.

   if (fLineStyle == lstyle) return;

   fLineStyle = lstyle;
   fPenModified = kTRUE;
}

//______________________________________________________________________________
void TGWin32::UpdateLineStyle()
{
   // Update line style

   static Int_t dashed[2] = { 3, 3 };
   static Int_t dotted[2] = { 1, 2 };
   static Int_t dasheddotted[4] = { 3, 4, 1, 4 };

   if (fLineStyle <= 1) {
      SetLineType(0, 0);
   } else if (fLineStyle == 2) {
      SetLineType(2, dashed);
   } else if (fLineStyle == 3) {
      SetLineType(2, dotted);
   } else if (fLineStyle == 4) {
      SetLineType(4, dasheddotted);
   } else {
      TString st = (TString)gStyle->GetLineStyleString(fLineStyle);
      TObjArray *tokens = st.Tokenize(" ");
      Int_t nt;
      nt = tokens->GetEntries();
      Int_t *linestyle = new Int_t[nt];
      for (Int_t j = 0; j<nt; j++) {
         Int_t it;
         sscanf(((TObjString*)tokens->At(j))->GetName(), "%d", &it);
         linestyle[j] = (Int_t)(it/4);
      }
      SetLineType(nt,linestyle);
      delete [] linestyle;
      delete tokens;
   }
   fPenModified = kFALSE;
}

//______________________________________________________________________________
void TGWin32::SetLineWidth(Width_t width)
{
   // Set line width.
   // width   : line width in pixels

   if ((fLineWidth==width) || (width<0)) return;

   if (width == 1) {
      fLineWidth = 0;
   } else {
      fLineWidth = width;
   }

   fPenModified = kTRUE;
}

//______________________________________________________________________________
void TGWin32::SetMarkerColor(Color_t cindex)
{
   // Set color index for markers.

   if ((cindex<0) || (cindex==fMarkerColor)) return;
   fMarkerColor = cindex;
   fMarkerColorModified = kTRUE;
}

//______________________________________________________________________________
void TGWin32::UpdateMarkerColor()
{
   //

   SetColor(gGCmark, Int_t(fMarkerColor));
   fMarkerColorModified = kFALSE;
}

//______________________________________________________________________________
void TGWin32::SetMarkerSize(Float_t msize)
{
   // Set marker size index.
   // msize  : marker scale factor

   if ((msize==fMarkerSize) || (msize<0)) return;

   fMarkerSize = msize;
   SetMarkerStyle(-fMarkerStyle);
}

//______________________________________________________________________________
void TGWin32::SetMarkerType(int type, int n, GdkPoint * xy)
{
   // Set marker type.
   // type      : marker type
   // n         : length of marker description
   // xy        : list of points describing marker shape
   //
   // if n == 0 marker is a single point
   // if TYPE == 0 marker is hollow circle of diameter N
   // if TYPE == 1 marker is filled circle of diameter N
   // if TYPE == 2 marker is a hollow polygon describe by line XY
   // if TYPE == 3 marker is a filled polygon describe by line XY
   // if TYPE == 4 marker is described by segmented line XY
   //   e.g. TYPE=4,N=4,XY=(-3,0,3,0,0,-3,0,3) sets a plus shape of 7x7 pixels

   gMarker.type = type;
   gMarker.n = n < kMAXMK ? n : kMAXMK;
   if (gMarker.type >= 2) {
      for (int i = 0; i < gMarker.n; i++) {
         gMarker.xy[i] = xy[i];
      }
   }
}

//______________________________________________________________________________
void TGWin32::SetMarkerStyle(Style_t markerstyle)
{
   // Set marker style.

   if ((fMarkerStyle==markerstyle) || (markerstyle >= 35)) return;
   fMarkerStyle = TMath::Abs(markerstyle);
   fMarkerStyleModified = kTRUE;
}

//______________________________________________________________________________
void TGWin32::UpdateMarkerStyle()
{
   //

   static GdkPoint shape[15];

   Int_t im = Int_t(4 * fMarkerSize + 0.5);

   if (fMarkerStyle == 2) {
      // + shaped marker
      shape[0].x = -im;
      shape[0].y = 0;
      shape[1].x = im;
      shape[1].y = 0;
      shape[2].x = 0;
      shape[2].y = -im;
      shape[3].x = 0;
      shape[3].y = im;
      SetMarkerType(4, 4, shape);
   } else if (fMarkerStyle == 3 || fMarkerStyle == 31) {
      // * shaped marker
      shape[0].x = -im;
      shape[0].y = 0;
      shape[1].x = im;
      shape[1].y = 0;
      shape[2].x = 0;
      shape[2].y = -im;
      shape[3].x = 0;
      shape[3].y = im;
      im = Int_t(0.707 * Float_t(im) + 0.5);
      shape[4].x = -im;
      shape[4].y = -im;
      shape[5].x = im;
      shape[5].y = im;
      shape[6].x = -im;
      shape[6].y = im;
      shape[7].x = im;
      shape[7].y = -im;
      SetMarkerType(4, 8, shape);
   } else if (fMarkerStyle == 4 || fMarkerStyle == 24) {
      // O shaped marker
      SetMarkerType(0, im * 2, shape);
   } else if (fMarkerStyle == 5) {
      // X shaped marker
      im = Int_t(0.707 * Float_t(im) + 0.5);
      shape[0].x = -im;
      shape[0].y = -im;
      shape[1].x = im;
      shape[1].y = im;
      shape[2].x = -im;
      shape[2].y = im;
      shape[3].x = im;
      shape[3].y = -im;
      SetMarkerType(4, 4, shape);
   } else if (fMarkerStyle == 6) {
      // + shaped marker (with 1 pixel)
      shape[0].x = -1;
      shape[0].y = 0;
      shape[1].x = 1;
      shape[1].y = 0;
      shape[2].x = 0;
      shape[2].y = -1;
      shape[3].x = 0;
      shape[3].y = 1;
      SetMarkerType(4, 4, shape);
   } else if (fMarkerStyle == 7) {
      // . shaped marker (with 9 pixel)
      shape[0].x = -1;
      shape[0].y = 1;
      shape[1].x = 1;
      shape[1].y = 1;
      shape[2].x = -1;
      shape[2].y = 0;
      shape[3].x = 1;
      shape[3].y = 0;
      shape[4].x = -1;
      shape[4].y = -1;
      shape[5].x = 1;
      shape[5].y = -1;
      SetMarkerType(4, 6, shape);
   } else if (fMarkerStyle == 8 || fMarkerStyle == 20) {
      // O shaped marker (filled)
      SetMarkerType(1, im * 2, shape);
   } else if (fMarkerStyle == 21) {
      // full square
      shape[0].x = -im;
      shape[0].y = -im;
      shape[1].x = im;
      shape[1].y = -im;
      shape[2].x = im;
      shape[2].y = im;
      shape[3].x = -im;
      shape[3].y = im;
      shape[4].x = -im;
      shape[4].y = -im;
      SetMarkerType(3, 5, shape);
   } else if (fMarkerStyle == 22) {
      // full triangle up
      shape[0].x = -im;
      shape[0].y = im;
      shape[1].x = im;
      shape[1].y = im;
      shape[2].x = 0;
      shape[2].y = -im;
      shape[3].x = -im;
      shape[3].y = im;
      SetMarkerType(3, 4, shape);
   } else if (fMarkerStyle == 23) {
      // full triangle down
      shape[0].x = 0;
      shape[0].y = im;
      shape[1].x = im;
      shape[1].y = -im;
      shape[2].x = -im;
      shape[2].y = -im;
      shape[3].x = 0;
      shape[3].y = im;
      SetMarkerType(3, 4, shape);
   } else if (fMarkerStyle == 25) {
      // open square
      shape[0].x = -im;
      shape[0].y = -im;
      shape[1].x = im;
      shape[1].y = -im;
      shape[2].x = im;
      shape[2].y = im;
      shape[3].x = -im;
      shape[3].y = im;
      shape[4].x = -im;
      shape[4].y = -im;
      SetMarkerType(2, 5, shape);
   } else if (fMarkerStyle == 26) {
      // open triangle up
      shape[0].x = -im;
      shape[0].y = im;
      shape[1].x = im;
      shape[1].y = im;
      shape[2].x = 0;
      shape[2].y = -im;
      shape[3].x = -im;
      shape[3].y = im;
      SetMarkerType(2, 4, shape);
   } else if (fMarkerStyle == 27) {
      // open losange
      Int_t imx = Int_t(2.66 * fMarkerSize + 0.5);
      shape[0].x = -imx;
      shape[0].y = 0;
      shape[1].x = 0;
      shape[1].y = -im;
      shape[2].x = imx;
      shape[2].y = 0;
      shape[3].x = 0;
      shape[3].y = im;
      shape[4].x = -imx;
      shape[4].y = 0;
      SetMarkerType(2, 5, shape);
   } else if (fMarkerStyle == 28) {
      // open cross
      Int_t imx = Int_t(1.33 * fMarkerSize + 0.5);
      shape[0].x = -im;
      shape[0].y = -imx;
      shape[1].x = -imx;
      shape[1].y = -imx;
      shape[2].x = -imx;
      shape[2].y = -im;
      shape[3].x = imx;
      shape[3].y = -im;
      shape[4].x = imx;
      shape[4].y = -imx;
      shape[5].x = im;
      shape[5].y = -imx;
      shape[6].x = im;
      shape[6].y = imx;
      shape[7].x = imx;
      shape[7].y = imx;
      shape[8].x = imx;
      shape[8].y = im;
      shape[9].x = -imx;
      shape[9].y = im;
      shape[10].x = -imx;
      shape[10].y = imx;
      shape[11].x = -im;
      shape[11].y = imx;
      shape[12].x = -im;
      shape[12].y = -imx;
      SetMarkerType(2, 13, shape);
   } else if (fMarkerStyle == 29) {
      // full star pentagone
      Int_t im1 = Int_t(0.66 * fMarkerSize + 0.5);
      Int_t im2 = Int_t(2.00 * fMarkerSize + 0.5);
      Int_t im3 = Int_t(2.66 * fMarkerSize + 0.5);
      Int_t im4 = Int_t(1.33 * fMarkerSize + 0.5);
      shape[0].x = -im;
      shape[0].y = im4;
      shape[1].x = -im2;
      shape[1].y = -im1;
      shape[2].x = -im3;
      shape[2].y = -im;
      shape[3].x = 0;
      shape[3].y = -im2;
      shape[4].x = im3;
      shape[4].y = -im;
      shape[5].x = im2;
      shape[5].y = -im1;
      shape[6].x = im;
      shape[6].y = im4;
      shape[7].x = im4;
      shape[7].y = im4;
      shape[8].x = 0;
      shape[8].y = im;
      shape[9].x = -im4;
      shape[9].y = im4;
      shape[10].x = -im;
      shape[10].y = im4;
      SetMarkerType(3, 11, shape);
   } else if (fMarkerStyle == 30) {
      // open star pentagone
      Int_t im1 = Int_t(0.66 * fMarkerSize + 0.5);
      Int_t im2 = Int_t(2.00 * fMarkerSize + 0.5);
      Int_t im3 = Int_t(2.66 * fMarkerSize + 0.5);
      Int_t im4 = Int_t(1.33 * fMarkerSize + 0.5);
      shape[0].x = -im;
      shape[0].y = im4;
      shape[1].x = -im2;
      shape[1].y = -im1;
      shape[2].x = -im3;
      shape[2].y = -im;
      shape[3].x = 0;
      shape[3].y = -im2;
      shape[4].x = im3;
      shape[4].y = -im;
      shape[5].x = im2;
      shape[5].y = -im1;
      shape[6].x = im;
      shape[6].y = im4;
      shape[7].x = im4;
      shape[7].y = im4;
      shape[8].x = 0;
      shape[8].y = im;
      shape[9].x = -im4;
      shape[9].y = im4;
      shape[10].x = -im;
      shape[10].y = im4;
      SetMarkerType(2, 11, shape);
   } else if (fMarkerStyle == 32) {
      // open triangle down
      shape[0].x =   0;  shape[0].y = im;
      shape[1].x =  im;  shape[1].y = -im;
      shape[2].x = -im;  shape[2].y = -im;
      shape[3].x =   0;  shape[3].y = im;
      SetMarkerType(2,4,shape);   
   } else if (fMarkerStyle == 33) {
      // full losange
      Int_t imx = Int_t(2.66*fMarkerSize + 0.5);
      shape[0].x =-imx;  shape[0].y = 0;  
      shape[1].x =   0;  shape[1].y = -im;
      shape[2].x = imx;  shape[2].y = 0;  
      shape[3].x =   0;  shape[3].y = im; 
      shape[4].x =-imx;  shape[4].y = 0;  
      SetMarkerType(3,5,shape);
   } else if (fMarkerStyle == 34) {
      // full cross
      Int_t imx = Int_t(1.33*fMarkerSize + 0.5);
      shape[0].x = -im;  shape[0].y =-imx;
      shape[1].x =-imx;  shape[1].y =-imx;
      shape[2].x =-imx;  shape[2].y = -im;
      shape[3].x = imx;  shape[3].y = -im;
      shape[4].x = imx;  shape[4].y =-imx;
      shape[5].x =  im;  shape[5].y =-imx;
      shape[6].x =  im;  shape[6].y = imx;
      shape[7].x = imx;  shape[7].y = imx;
      shape[8].x = imx;  shape[8].y = im;
      shape[9].x =-imx;  shape[9].y = im;
      shape[10].x=-imx;  shape[10].y= imx;
      shape[11].x= -im;  shape[11].y= imx;
      shape[12].x= -im;  shape[12].y=-imx;
      SetMarkerType(3,13,shape);
   } else {
      // single dot
      SetMarkerType(0, 0, shape);
   }
   fMarkerStyleModified = kFALSE;
}

//______________________________________________________________________________
void TGWin32::SetOpacity(Int_t percent)
{
   // Set opacity of a window. This image manipulation routine works
   // by adding to a percent amount of neutral to each pixels RGB.
   // Since it requires quite some additional color map entries is it
   // only supported on displays with more than > 8 color planes (> 256
   // colors)

   Int_t depth = gdk_visual_get_best_depth();

   if (depth <= 8) return;
   if (percent == 0) return;

   // if 100 percent then just make white
   ULong_t *orgcolors = 0, *tmpc = 0;
   Int_t maxcolors = 0, ncolors, ntmpc = 0;

   // save previous allocated colors, delete at end when not used anymore
   if (gCws->new_colors) {
      tmpc = gCws->new_colors;
      ntmpc = gCws->ncolors;
   }
   // get pixmap from server as image
   GdkImage *image = gdk_image_get((GdkDrawable*)gCws->drawing, 0, 0,
                                   gCws->width, gCws->height);

   // collect different image colors
   int x, y;
   for (y = 0; y < (int) gCws->height; y++) {
      for (x = 0; x < (int) gCws->width; x++) {
         ULong_t pixel = GetPixelImage((Drawable_t)image, x, y);
         CollectImageColors(pixel, orgcolors, ncolors, maxcolors);
      }
   }
   if (ncolors == 0) {
      gdk_image_unref(image);
      ::operator delete(orgcolors);
      return;
   }
   // create opaque counter parts
   MakeOpaqueColors(percent, orgcolors, ncolors);

   // put opaque colors in image
   for (y = 0; y < (int) gCws->height; y++) {
      for (x = 0; x < (int) gCws->width; x++) {
         ULong_t pixel = GetPixelImage((Drawable_t)image, x, y);
         Int_t idx = FindColor(pixel, orgcolors, ncolors);
         PutPixel((Drawable_t)image, x, y, gCws->new_colors[idx]);
      }
   }

   // put image back in pixmap on server
   gdk_draw_image(gCws->drawing, gGCpxmp, (GdkImage *)image,
                  0, 0, 0, 0, gCws->width, gCws->height);
   GdiFlush();

   // clean up
   if (tmpc) {
      gdk_colors_free((GdkColormap *)fColormap, tmpc, ntmpc, 0);
      delete[]tmpc;
   }
   gdk_image_unref(image);
   ::operator delete(orgcolors);
}

//______________________________________________________________________________
void TGWin32::MakeOpaqueColors(Int_t percent, ULong_t *orgcolors, Int_t ncolors)
{
   // Get RGB values for orgcolors, add percent neutral to the RGB and
   // allocate new_colors.

   Int_t ret;
   if (ncolors <= 0) return;
   GdkColor *xcol = new GdkColor[ncolors];

   int i;
   for (i = 0; i < ncolors; i++) {
      xcol[i].pixel = orgcolors[i];
      xcol[i].red = xcol[i].green = xcol[i].blue = 0;
   }

   GdkColorContext *cc;
   cc = gdk_color_context_new(gdk_visual_get_system(), (GdkColormap *)fColormap);
   gdk_color_context_query_colors(cc, xcol, ncolors);
   gdk_color_context_free(cc);

   UShort_t add = percent * kBIGGEST_RGB_VALUE / 100;

   Int_t val;
   for (i = 0; i < ncolors; i++) {
      val = xcol[i].red + add;
      if (val > kBIGGEST_RGB_VALUE) {
         val = kBIGGEST_RGB_VALUE;
      }
      xcol[i].red = (UShort_t) val;
      val = xcol[i].green + add;
      if (val > kBIGGEST_RGB_VALUE) {
         val = kBIGGEST_RGB_VALUE;
      }
      xcol[i].green = (UShort_t) val;
      val = xcol[i].blue + add;
      if (val > kBIGGEST_RGB_VALUE) {
         val = kBIGGEST_RGB_VALUE;
      }
      xcol[i].blue = (UShort_t) val;

      ret = gdk_color_alloc((GdkColormap *)fColormap, &xcol[i]);

      if (!ret) {
         Warning("MakeOpaqueColors",
                 "failed to allocate color %hd, %hd, %hd", xcol[i].red,
                 xcol[i].green, xcol[i].blue);
      // assumes that in case of failure xcol[i].pixel is not changed
      }
   }

   gCws->new_colors = new ULong_t[ncolors];
   gCws->ncolors = ncolors;

   for (i = 0; i < ncolors; i++) {
      gCws->new_colors[i] = xcol[i].pixel;
   }

   delete []xcol;
}

//______________________________________________________________________________
Int_t TGWin32::FindColor(ULong_t pixel, ULong_t * orgcolors, Int_t ncolors)
{
   // Returns index in orgcolors (and new_colors) for pixel.

   for (int i = 0; i < ncolors; i++) {
      if (pixel == orgcolors[i]) return i;
   }
   Error("FindColor", "did not find color, should never happen!");

   return 0;
}

//______________________________________________________________________________
void TGWin32::SetRGB(int cindex, float r, float g, float b)
{
   // Set color intensities for given color index.
   // cindex     : color index
   // r,g,b      : red, green, blue intensities between 0.0 and 1.0

   GdkColor xcol;

   if (fColormap && cindex >= 0) {
      xcol.red = (unsigned short) (r * kBIGGEST_RGB_VALUE);
      xcol.green = (unsigned short) (g * kBIGGEST_RGB_VALUE);
      xcol.blue = (unsigned short) (b * kBIGGEST_RGB_VALUE);
      xcol.pixel = RGB(xcol.red, xcol.green, xcol.blue);

      XColor_t &col = GetColor(cindex);
      if (col.fDefined) {
         // if color is already defined with same rgb just return
         if (col.color.red  == xcol.red && col.color.green == xcol.green &&
             col.color.blue == xcol.blue)
            return;
         col.fDefined = kFALSE;
         gdk_colormap_free_colors((GdkColormap *) fColormap,
                                  (GdkColor *)&col, 1);
      }

      Int_t ret = gdk_colormap_alloc_color(fColormap, &xcol, 1, 1);
      if (ret != 0) {
         col.fDefined = kTRUE;
         col.color.pixel   = xcol.pixel;
         col.color.red     = xcol.red;
         col.color.green   = xcol.green;
         col.color.blue    = xcol.blue;
      }
   }
}

//______________________________________________________________________________
void TGWin32::SetTextAlign(Short_t talign)
{
   // Set text alignment.
   // txalh   : horizontal text alignment
   // txalv   : vertical text alignment

   static Short_t current = 0;
   if (talign==current) return;
   current = talign;

   Int_t txalh = talign / 10;
   Int_t txalv = talign % 10;
   fTextAlignH = txalh;
   fTextAlignV = txalv;

   switch (txalh) {

   case 0:
   case 1:
      switch (txalv) {          //left
      case 1:
         fTextAlign = 7;        //bottom
         break;
      case 2:
         fTextAlign = 4;        //center
         break;
      case 3:
         fTextAlign = 1;        //top
         break;
      }
      break;
   case 2:
      switch (txalv) {          //center
      case 1:
         fTextAlign = 8;        //bottom
         break;
      case 2:
         fTextAlign = 5;        //center
         break;
      case 3:
         fTextAlign = 2;        //top
         break;
      }
      break;
   case 3:
      switch (txalv) {          //right
      case 1:
         fTextAlign = 9;        //bottom
         break;
      case 2:
         fTextAlign = 6;        //center
         break;
      case 3:
         fTextAlign = 3;        //top
         break;
      }
      break;
   }
   TAttText::SetTextAlign(fTextAlign);
}

//______________________________________________________________________________
void TGWin32::SetTextColor(Color_t cindex)
{
   // Set color index for text.

   static Int_t current = 0;
   GdkGCValues values;
   if ((cindex < 0) || (Int_t(cindex)==current)) return;

   SetColor(gGCtext, Int_t(cindex));
   gdk_gc_get_values(gGCtext, &values);
   gdk_gc_set_foreground(gGCinvt, &values.background);
   gdk_gc_set_background(gGCinvt, &values.foreground);
   gdk_gc_set_background(gGCtext, (GdkColor *) & GetColor(0).color);
   current = Int_t(cindex);
}

//______________________________________________________________________________
void TGWin32::Sync(int mode)
{
}

//______________________________________________________________________________
void TGWin32::UpdateWindow(int mode)
{
   // Update display.
   // mode : (1) update
   //        (0) sync
   //
   // Synchronise client and server once (not permanent).
   // Copy the pixmap gCws->drawing on the window gCws->window
   // if the double buffer is on.

   if (gCws && gCws->double_buffer) {
      gdk_window_copy_area(gCws->window, gGCpxmp, 0, 0,
                           gCws->drawing, 0, 0, gCws->width, gCws->height);
   }
   Update(mode);
}

//______________________________________________________________________________
void TGWin32::Warp(int ix, int iy, Window_t id)
{
   // Set pointer position.
   // ix       : New X coordinate of pointer
   // iy       : New Y coordinate of pointer
   // Coordinates are relative to the origin of the window id
   // or to the origin of the current window if id == 0.

   if (!id) return;

   POINT cpt, tmp;
   HWND dw;
   if (!id)
      dw = (HWND) GDK_DRAWABLE_XID((GdkWindow *)gCws->window);
   else
      dw = (HWND) GDK_DRAWABLE_XID((GdkWindow *)id);
   GetCursorPos(&cpt);
   tmp.x = ix > 0 ? ix : cpt.x;
   tmp.y = iy > 0 ? iy : cpt.y;
   ClientToScreen(dw, &tmp);
   SetCursorPos(tmp.x, tmp.y);
}

//______________________________________________________________________________
void TGWin32::WritePixmap(int wid, unsigned int w, unsigned int h,
                          char *pxname)
{
   // Write the pixmap wid in the bitmap file pxname.
   // wid         : Pixmap address
   // w,h         : Width and height of the pixmap.
   // lenname     : pixmap name length
   // pxname      : pixmap name

   int wval, hval;
   wval = w;
   hval = h;

   if (!fWindows) return;
   gTws = &fWindows[wid];
//   XWriteBitmapFile(fDisplay,pxname,(Pixmap)gTws->drawing,wval,hval,-1,-1);
}


//
// Functions for GIFencode()
//

static FILE *gGifFile;           // output unit used WriteGIF and PutByte
static GdkImage *gGifImage = 0;  // image used in WriteGIF and GetPixel

extern "C" {
   int GIFquantize(UInt_t width, UInt_t height, Int_t * ncol, Byte_t * red,
                   Byte_t * green, Byte_t * blue, Byte_t * outputBuf,
                   Byte_t * outputCmap);
   long GIFencode(int Width, int Height, Int_t Ncol, Byte_t R[],
                  Byte_t G[], Byte_t B[], Byte_t ScLine[],
                  void (*get_scline) (int, int, Byte_t *),
                  void (*pb) (Byte_t));
   int GIFdecode(Byte_t * GIFarr, Byte_t * PIXarr, int *Width, int *Height,
                 int *Ncols, Byte_t * R, Byte_t * G, Byte_t * B);
   int GIFinfo(Byte_t * GIFarr, int *Width, int *Height, int *Ncols);
}


//______________________________________________________________________________
static void GetPixel(int y, int width, Byte_t * scline)
{
   // Get pixels in line y and put in array scline.

   for (int i = 0; i < width; i++) {
       scline[i] = Byte_t(GetPixelImage((Drawable_t)gGifImage, i, y));
   }
}

//______________________________________________________________________________
static void PutByte(Byte_t b)
{
   // Put byte b in output stream.

   if (ferror(gGifFile) == 0) fputc(b, gGifFile);
}

//______________________________________________________________________________
void TGWin32::ImgPickPalette(GdkImage * image, Int_t & ncol, Int_t * &R,
                             Int_t * &G, Int_t * &B)
{
   // Returns in R G B the ncol colors of the palette used by the image.
   // The image pixels are changed to index values in these R G B arrays.
   // This produces a colormap with only the used colors (so even on displays
   // with more than 8 planes we will be able to create GIF's when the image
   // contains no more than 256 different colors). If it does contain more
   // colors we will have to use GIFquantize to reduce the number of colors.
   // The R G B arrays must be deleted by the caller.

   ULong_t *orgcolors = 0;
   Int_t maxcolors = 0, ncolors;

   // collect different image colors
   int x, y;
   for (x = 0; x < (int) gCws->width; x++) {
      for (y = 0; y < (int) gCws->height; y++) {
         ULong_t pixel = GetPixelImage((Drawable_t)image, x, y);
         CollectImageColors(pixel, orgcolors, ncolors, maxcolors);
      }
   }

   // get RGB values belonging to pixels
   GdkColor *xcol = new GdkColor[ncolors];

   int i;
   for (i = 0; i < ncolors; i++) {
      xcol[i].pixel = orgcolors[i];
//      xcol[i].red   = xcol[i].green = xcol[i].blue = 0;
      xcol[i].red = GetRValue(xcol[i].pixel);
      xcol[i].green = GetGValue(xcol[i].pixel);
      xcol[i].blue = GetBValue(xcol[i].pixel);
   }

   GdkColorContext *cc;
   cc =  gdk_color_context_new(gdk_visual_get_system(), (GdkColormap *)fColormap);
   gdk_color_context_query_colors(cc, xcol, ncolors);
   gdk_color_context_free(cc);

   // create RGB arrays and store RGB's for each color and set number of colors
   // (space must be delete by caller)
   R = new Int_t[ncolors];
   G = new Int_t[ncolors];
   B = new Int_t[ncolors];

   for (i = 0; i < ncolors; i++) {
      R[i] = xcol[i].red;
      G[i] = xcol[i].green;
      B[i] = xcol[i].blue;
   }
   ncol = ncolors;

   // update image with indices (pixels) into the new RGB colormap
   for (x = 0; x < (int) gCws->width; x++) {
      for (y = 0; y < (int) gCws->height; y++) {
         ULong_t pixel = GetPixelImage((Drawable_t)image, x, y);
         Int_t idx = FindColor(pixel, orgcolors, ncolors);
         PutPixel((Drawable_t)image, x, y, idx);
      }
   }

   // cleanup
   delete[]xcol;
   ::operator delete(orgcolors);
}

//______________________________________________________________________________
Int_t TGWin32::WriteGIF(char *name)
{
   // Writes the current window into GIF file.

   Byte_t scline[2000], r[256], b[256], g[256];
   Int_t *R, *G, *B;
   Int_t ncol, maxcol, i;

   if (gGifImage) {
      gdk_image_unref((GdkImage *)gGifImage);
   }

   gGifImage = gdk_image_get((GdkDrawable*)gCws->drawing, 0, 0,
                             gCws->width, gCws->height);

   ImgPickPalette(gGifImage, ncol, R, G, B);

   if (ncol > 256) {
      //GIFquantize(...);
      Error("WriteGIF",
            "can not create GIF of image containing more than 256 colors");
      delete[]R;
      delete[]G;
      delete[]B;
      return 0;
   }

   maxcol = 0;
   for (i = 0; i < ncol; i++) {
      if (maxcol < R[i]) maxcol = R[i];
      if (maxcol < G[i]) maxcol = G[i];
      if (maxcol < B[i]) maxcol = B[i];
      r[i] = 0;
      g[i] = 0;
      b[i] = 0;
   }
   if (maxcol != 0) {
      for (i = 0; i < ncol; i++) {
         r[i] = R[i] * 255 / maxcol;
         g[i] = G[i] * 255 / maxcol;
         b[i] = B[i] * 255 / maxcol;
      }
   }

   gGifFile = fopen(name, "wb");

   if (gGifFile) {
      GIFencode(gCws->width, gCws->height,
          ncol, r, g, b, scline, ::GetPixel, PutByte);
      fclose(gGifFile);
      i = 1;
    } else {
      Error("WriteGIF","cannot write file: %s",name);
      i = 0;
   }
   delete[]R;
   delete[]G;
   delete[]B;

   return i;
}

//______________________________________________________________________________
void TGWin32::PutImage(int offset, int itran, int x0, int y0, int nx,
                       int ny, int xmin, int ymin, int xmax, int ymax,
                       unsigned char *image, Drawable_t wid)
{
   // Draw image.

   const int MAX_SEGMENT = 20;
   int i, n, x, y, xcur, x1, x2, y1, y2;
   unsigned char *jimg, *jbase, icol;
   int nlines[256];
   GdkSegment lines[256][MAX_SEGMENT];
   GdkDrawable *id;

   if (wid) {
      id = (GdkDrawable*)wid;
   } else {
      id = gCws->drawing;
   }

   for (i = 0; i < 256; i++) nlines[i] = 0;

   x1 = x0 + xmin;
   y1 = y0 + ny - ymax - 1;
   x2 = x0 + xmax;
   y2 = y0 + ny - ymin - 1;
   jbase = image + (ymin - 1) * nx + xmin;

   for (y = y2; y >= y1; y--) {
      xcur = x1;
      jbase += nx;
      for (jimg = jbase, icol = *jimg++, x = x1 + 1; x <= x2; jimg++, x++) {
         if (icol != *jimg) {
            if (icol != itran) {
               n = nlines[icol]++;
               lines[icol][n].x1 = xcur;
               lines[icol][n].y1 = y;
               lines[icol][n].x2 = x - 1;
               lines[icol][n].y2 = y;
               if (nlines[icol] == MAX_SEGMENT) {
                  SetColor(gGCline, (int) icol + offset);
                  gdk_win32_draw_segments(id, (GdkGC *) gGCline,
                                       (GdkSegment *) &lines[icol][0], MAX_SEGMENT);
                  nlines[icol] = 0;
               }
            }
            icol = *jimg;
            xcur = x;
         }
      }
      if (icol != itran) {
         n = nlines[icol]++;
         lines[icol][n].x1 = xcur;
         lines[icol][n].y1 = y;
         lines[icol][n].x2 = x - 1;
         lines[icol][n].y2 = y;
         if (nlines[icol] == MAX_SEGMENT) {
            SetColor(gGCline, (int) icol + offset);
            gdk_win32_draw_segments(id, (GdkGC *) gGCline,
                              (GdkSegment *)&lines[icol][0], MAX_SEGMENT);
            nlines[icol] = 0;
         }
      }
   }

   for (i = 0; i < 256; i++) {
      if (nlines[i] != 0) {
         SetColor(gGCline, i + offset);
         gdk_win32_draw_segments(id, (GdkGC *) gGCline,
                           (GdkSegment *)&lines[icol][0], nlines[i]);
      }
   }
}

//______________________________________________________________________________
Pixmap_t TGWin32::ReadGIF(int x0, int y0, const char *file, Window_t id)
{
   // If id is NULL - loads the specified gif file at position [x0,y0] in the
   // current window. Otherwise creates pixmap from gif file

   FILE *fd;
   Seek_t filesize;
   unsigned char *GIFarr, *PIXarr, R[256], G[256], B[256], *j1, *j2, icol;
   int i, j, k, width, height, ncolor, irep, offset;
   float rr, gg, bb;
   Pixmap_t pic = 0;

   fd = fopen(file, "r+b");
   if (!fd) {
      Error("ReadGIF", "unable to open GIF file");
      return pic;
   }

   fseek(fd, 0L, 2);
   filesize = Seek_t(ftell(fd));
   fseek(fd, 0L, 0);

   if (!(GIFarr = (unsigned char *) calloc(filesize + 256, 1))) {
      fclose(fd);
      Error("ReadGIF", "unable to allocate array for gif");
      return pic;
   }

   if (fread(GIFarr, filesize, 1, fd) != 1) {
      fclose(fd);
      Error("ReadGIF", "GIF file read failed");
      return pic;
   }
   fclose(fd);

   irep = GIFinfo(GIFarr, &width, &height, &ncolor);
   if (irep != 0) {
      return pic;
   }

   if (!(PIXarr = (unsigned char *) calloc((width * height), 1))) {
      Error("ReadGIF", "unable to allocate array for image");
      return pic;
   }

   irep = GIFdecode(GIFarr, PIXarr, &width, &height, &ncolor, R, G, B);
   if (irep != 0) {
      return pic;
   }
   // S E T   P A L E T T E

   offset = 8;

   for (i = 0; i < ncolor; i++) {
      rr = R[i] / 255.;
      gg = G[i] / 255.;
      bb = B[i] / 255.;
      j = i + offset;
      SetRGB(j, rr, gg, bb);
   }

   // O U T P U T   I M A G E

   for (i = 1; i <= height / 2; i++) {
      j1 = PIXarr + (i - 1) * width;
      j2 = PIXarr + (height - i) * width;
      for (k = 0; k < width; k++) {
         icol = *j1;
         *j1++ = *j2;
         *j2++ = icol;
      }
   }

   if (id) pic = CreatePixmap(id, width, height);
   PutImage(offset, -1, x0, y0, width, height, 0, 0, width-1, height-1, PIXarr, pic);

   if (pic) return pic;
   else if (gCws->drawing) return  (Pixmap_t)gCws->drawing;
   else return 0;
}

//////////////////////////// GWin32Gui //////////////////////////////////////////
//______________________________________________________________________________
void TGWin32::MapWindow(Window_t id)
{
   // Map window on screen.

   if (!id) return;

   gdk_window_show((GdkWindow *)id);
   if ((GDK_DRAWABLE_TYPE((GdkWindow *)id) != GDK_WINDOW_TEMP) &&
       (GetParent(id) == GetDefaultRootWindow())) {
      HWND window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)id);
      ::SetForegroundWindow(window);
   }
}

//______________________________________________________________________________
void TGWin32::MapSubwindows(Window_t id)
{
   //

   if (!id) return;
   EnumChildWindows((HWND)GDK_DRAWABLE_XID((GdkWindow *)id),
                    EnumChildProc, (LPARAM) NULL);
}

//______________________________________________________________________________
void TGWin32::MapRaised(Window_t id)
{
   // Map window on screen and put on top of all windows.

   if (!id) return;

   HWND hwnd = ::GetForegroundWindow();
   HWND window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)id);
   gdk_window_show((GdkWindow *)id);
   if (GDK_DRAWABLE_TYPE((GdkWindow *)id) != GDK_WINDOW_TEMP) {
      ::BringWindowToTop(window);
      if (GDK_DRAWABLE_TYPE((GdkWindow *)id) != GDK_WINDOW_CHILD)
         ::SetForegroundWindow(window);
   }

   if (gConsoleWindow && (hwnd == (HWND)gConsoleWindow)) {
      RECT r1, r2, r3;
      ::GetWindowRect((HWND)gConsoleWindow, &r1);
      HWND fore = ::GetForegroundWindow();
      ::GetWindowRect(fore, &r2);
      if (!::IntersectRect(&r3, &r2, &r1)) {
         ::SetForegroundWindow((HWND)gConsoleWindow);
      }
   }
}

//______________________________________________________________________________
void TGWin32::UnmapWindow(Window_t id)
{
   // Unmap window from screen.

   if (!id) return;

   gdk_window_hide((GdkWindow *) id);
}

//______________________________________________________________________________
void TGWin32::DestroyWindow(Window_t id)
{
   // Destroy window.

   if (!id) return;

   // we need to unmap the window before to destroy it, in order to properly 
   // receive kUnmapNotify needed by gClient->WaitForUnmap()...
   gdk_window_hide((GdkWindow *) id);
   gdk_window_destroy((GdkDrawable *) id, kTRUE);
}

//______________________________________________________________________________
void TGWin32::DestroySubwindows(Window_t id)
{
   // Destroy all internal subwindows

   if (!id) return;

   gdk_window_destroy((GdkDrawable *) id, kFALSE);
}

//______________________________________________________________________________
void TGWin32::RaiseWindow(Window_t id)
{
   // Put window on top of window stack.

   if (!id) return;

   HWND window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)id);
   if (GDK_DRAWABLE_TYPE((GdkWindow *)id) == GDK_WINDOW_TEMP) {
       ::SetWindowPos(window, HWND_TOPMOST,  0, 0, 0, 0,
                      SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
   }
   else {
      ::BringWindowToTop(window);
      if (GDK_DRAWABLE_TYPE((GdkWindow *)id) != GDK_WINDOW_CHILD)
         ::SetForegroundWindow(window);
   }
}

//______________________________________________________________________________
void TGWin32::LowerWindow(Window_t id)
{
   // Lower window so it lays below all its siblings.

   if (!id) return;

   HWND window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)id);
   ::SetWindowPos(window, HWND_BOTTOM, 0, 0, 0, 0,
                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
}

//______________________________________________________________________________
void TGWin32::MoveWindow(Window_t id, Int_t x, Int_t y)
{
   // Move a window.

   if (!id) return;

   gdk_window_move((GdkDrawable *) id, x, y);
}

//______________________________________________________________________________
void TGWin32::MoveResizeWindow(Window_t id, Int_t x, Int_t y, UInt_t w,
                               UInt_t h)
{
   // Move and resize a window.

   if (!id) return;

   gdk_window_move_resize((GdkWindow *) id, x, y, w, h);
}

//______________________________________________________________________________
void TGWin32::ResizeWindow(Window_t id, UInt_t w, UInt_t h)
{
   // Resize the window.

   if (!id) return;

   // protect against potential negative values
   if (w >= (UInt_t)INT_MAX || h >= (UInt_t)INT_MAX)
      return;
   gdk_window_resize((GdkWindow *) id, w, h);
}

//______________________________________________________________________________
void TGWin32::IconifyWindow(Window_t id)
{
   // Iconify the window.

   if (!id) return;

   gdk_window_lower((GdkWindow *) id);
   ::CloseWindow((HWND)GDK_DRAWABLE_XID((GdkWindow *)id));
}

//______________________________________________________________________________
void TGWin32::ReparentWindow(Window_t id, Window_t pid, Int_t x, Int_t y)
{
   // Reparent window, make pid the new parent and position the window at
   // position (x,y) in new parent.

   if (!id) return;

   gdk_window_reparent((GdkWindow *)id, (GdkWindow *)pid, x, y);
}

//______________________________________________________________________________
void TGWin32::SetWindowBackground(Window_t id, ULong_t color)
{
   // Set the window background color.

   if (!id) return;

   GdkColor back;
   back.pixel = color;
   back.red = GetRValue(color);
   back.green = GetGValue(color);
   back.blue = GetBValue(color);

   gdk_window_set_background((GdkWindow *) id, &back);
}

//______________________________________________________________________________
void TGWin32::SetWindowBackgroundPixmap(Window_t id, Pixmap_t pxm)
{
   // Set pixmap as window background.

   if (!id) return;

   gdk_window_set_back_pixmap((GdkWindow *) id, (GdkPixmap *) pxm, 0);
}

//______________________________________________________________________________
Window_t TGWin32::CreateWindow(Window_t parent, Int_t x, Int_t y,
                               UInt_t w, UInt_t h, UInt_t border,
                               Int_t depth, UInt_t clss,
                               void *visual, SetWindowAttributes_t * attr,
                               UInt_t wtype)
{
   // Return handle to newly created gdk window.

   GdkWindowAttr xattr;
   GdkWindow *newWin;
   GdkColor background_color;
   ULong_t xmask = 0;

   if (attr) {
      MapSetWindowAttributes(attr, xmask, xattr);
      xattr.window_type = GDK_WINDOW_CHILD;
      if (wtype & kMainFrame) {
         xattr.window_type = GDK_WINDOW_TOPLEVEL;
      }
      if (wtype & kTransientFrame) {
         xattr.window_type = GDK_WINDOW_DIALOG;
      }
      if (wtype & kTempFrame) {
         xattr.window_type = GDK_WINDOW_TEMP;
      }
      newWin = gdk_window_new((GdkWindow *) parent, &xattr, xmask);
   } else {
      xattr.width = w;
      xattr.height = h;
      xattr.wclass = GDK_INPUT_OUTPUT;
      xattr.event_mask = 0L;    //GDK_ALL_EVENTS_MASK;
      xattr.event_mask |= GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK |
          GDK_PROPERTY_CHANGE_MASK;
//                          GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK;
      if (x >= 0) {
         xattr.x = x;
      } else {
         xattr.x = -1.0 * x;
      }
      if (y >= 0) {
         xattr.y = y;
      } else {
         xattr.y = -1.0 * y;
      }
      xattr.colormap = gdk_colormap_get_system();
      xattr.cursor = NULL;
      xattr.override_redirect = TRUE;
      if ((xattr.y > 0) && (xattr.x > 0)) {
         xmask = GDK_WA_X | GDK_WA_Y | GDK_WA_COLORMAP |
             GDK_WA_WMCLASS | GDK_WA_NOREDIR;
      } else {
         xmask = GDK_WA_COLORMAP | GDK_WA_WMCLASS | GDK_WA_NOREDIR;
      }
      if (visual != NULL) {
         xattr.visual = (GdkVisual *) visual;
         xmask |= GDK_WA_VISUAL;
      } else {
         xattr.visual = gdk_visual_get_system();
         xmask |= GDK_WA_VISUAL;
      }
      xattr.window_type = GDK_WINDOW_CHILD;
      if (wtype & kMainFrame) {
         xattr.window_type = GDK_WINDOW_TOPLEVEL;
      }
      if (wtype & kTransientFrame) {
         xattr.window_type = GDK_WINDOW_DIALOG;
      }
      if (wtype & kTempFrame) {
         xattr.window_type = GDK_WINDOW_TEMP;
      }
      newWin = gdk_window_new((GdkWindow *) parent, &xattr, xmask);
      gdk_window_set_events(newWin, (GdkEventMask) 0L);
   }
   if (border > 0) {
      gdk_window_set_decorations(newWin,
                                 (GdkWMDecoration) GDK_DECOR_BORDER);
   }
   if (attr) {
      if ((attr->fMask & kWABackPixmap)) {
         if (attr->fBackgroundPixmap == kNone) {
            gdk_window_set_back_pixmap(newWin, (GdkPixmap *) GDK_NONE, 0);
         } else if (attr->fBackgroundPixmap == kParentRelative) {
            gdk_window_set_back_pixmap(newWin, (GdkPixmap *) GDK_NONE, 1);
         } else {
            gdk_window_set_back_pixmap(newWin,
                                       (GdkPixmap *) attr->
                                       fBackgroundPixmap, 0);
         }
      }
      if ((attr->fMask & kWABackPixel)) {
         background_color.pixel = attr->fBackgroundPixel;
         background_color.red = GetRValue(attr->fBackgroundPixel);
         background_color.green = GetGValue(attr->fBackgroundPixel);
         background_color.blue = GetBValue(attr->fBackgroundPixel);
         gdk_window_set_background(newWin, &background_color);
      }
   }
   if (!fUseSysPointers) {
      ::SetClassLong((HWND)GDK_DRAWABLE_XID(newWin), GCL_HCURSOR, 
                     (LONG)GDK_CURSOR_XID(fCursors[kPointer]));
   }
   return (Window_t) newWin;
}

//______________________________________________________________________________
void TGWin32::MapEventMask(UInt_t & emask, UInt_t & xemask, Bool_t tox)
{
   // Map event mask to or from gdk.

   if (tox) {
      Long_t lxemask = 0L;
      if ((emask & kKeyPressMask)) {
         lxemask |= GDK_KEY_PRESS_MASK;
      }
      if ((emask & kKeyReleaseMask)) {
         lxemask |= GDK_KEY_RELEASE_MASK;
      }
      if ((emask & kButtonPressMask)) {
         lxemask |= GDK_BUTTON_PRESS_MASK;
      }
      if ((emask & kButtonReleaseMask)) {
         lxemask |= GDK_BUTTON_RELEASE_MASK;
      }
      if ((emask & kPointerMotionMask)) {
         lxemask |= GDK_POINTER_MOTION_MASK;
      }
      if ((emask & kButtonMotionMask)) {
         lxemask |= GDK_BUTTON_MOTION_MASK;
      }
      if ((emask & kExposureMask)) {
         lxemask |= GDK_EXPOSURE_MASK;
      }
      if ((emask & kStructureNotifyMask)) {
         lxemask |= GDK_STRUCTURE_MASK;
      }
      if ((emask & kEnterWindowMask)) {
         lxemask |= GDK_ENTER_NOTIFY_MASK;
      }
      if ((emask & kLeaveWindowMask)) {
         lxemask |= GDK_LEAVE_NOTIFY_MASK;
      }
      if ((emask & kFocusChangeMask)) {
         lxemask |= GDK_FOCUS_CHANGE_MASK;
      }
      xemask = (UInt_t) lxemask;
   } else {
      emask = 0;
      if ((xemask & GDK_KEY_PRESS_MASK)) {
         emask |= kKeyPressMask;
      }
      if ((xemask & GDK_KEY_RELEASE_MASK)) {
         emask |= kKeyReleaseMask;
      }
      if ((xemask & GDK_BUTTON_PRESS_MASK)) {
         emask |= kButtonPressMask;
      }
      if ((xemask & GDK_BUTTON_RELEASE_MASK)) {
         emask |= kButtonReleaseMask;
      }
      if ((xemask & GDK_POINTER_MOTION_MASK)) {
         emask |= kPointerMotionMask;
      }
      if ((xemask & GDK_BUTTON_MOTION_MASK)) {
         emask |= kButtonMotionMask;
      }
      if ((xemask & GDK_EXPOSURE_MASK)) {
         emask |= kExposureMask;
      }
      if ((xemask & GDK_STRUCTURE_MASK)) {
         emask |= kStructureNotifyMask;
      }
      if ((xemask & GDK_ENTER_NOTIFY_MASK)) {
         emask |= kEnterWindowMask;
      }
      if ((xemask & GDK_LEAVE_NOTIFY_MASK)) {
         emask |= kLeaveWindowMask;
      }
      if ((xemask & GDK_FOCUS_CHANGE_MASK)) {
         emask |= kFocusChangeMask;
      }
   }
}

//______________________________________________________________________________
void TGWin32::MapSetWindowAttributes(SetWindowAttributes_t * attr,
                                     ULong_t & xmask,
                                     GdkWindowAttr & xattr)
{
   // Map a SetWindowAttributes_t to a GdkWindowAttr structure.

   Mask_t mask = attr->fMask;
   xmask = 0;

   if ((mask & kWAOverrideRedirect)) {
      xmask |= GDK_WA_NOREDIR;
      xattr.override_redirect = attr->fOverrideRedirect;
   }
   if ((mask & kWAEventMask)) {
      UInt_t xmsk, msk = (UInt_t) attr->fEventMask;
      MapEventMask(msk, xmsk, kTRUE);
      xattr.event_mask = xmsk;
   }
   if ((mask & kWAColormap)) {
      xmask |= GDK_WA_COLORMAP;
      xattr.colormap = (GdkColormap *) attr->fColormap;
   }
   if ((mask & kWACursor)) {
      xmask |= GDK_WA_CURSOR;
      if (attr->fCursor != kNone) {
         xattr.cursor = (GdkCursor *) attr->fCursor;
      }
   }
   xattr.wclass = GDK_INPUT_OUTPUT;
}

//______________________________________________________________________________
void TGWin32::MapGCValues(GCValues_t & gval,
                          ULong_t & xmask, GdkGCValues & xgval, Bool_t tox)
{
   // Map a GCValues_t to a XCGValues structure if tox is true. Map
   // the other way in case tox is false.

   if (tox) {
      // map GCValues_t to XGCValues
      Mask_t mask = gval.fMask;
      xmask = 0;

      if ((mask & kGCFunction)) {
         xmask |= GDK_GC_FUNCTION;
         switch (gval.fFunction) {
         case kGXclear:
            xgval.function = GDK_CLEAR;
            break;
         case kGXand:
            xgval.function = GDK_AND;
            break;
         case kGXandReverse:
            xgval.function = GDK_AND_REVERSE;
            break;
         case kGXcopy:
            xgval.function = GDK_COPY;
            break;
         case kGXandInverted:
            xgval.function = GDK_AND_INVERT;
            break;
         case kGXnoop:
            xgval.function = GDK_NOOP;
            break;
         case kGXxor:
            xgval.function = GDK_XOR;
            break;
         case kGXor:
            xgval.function = GDK_OR;
            break;
         case kGXequiv:
            xgval.function = GDK_EQUIV;
            break;
         case kGXinvert:
            xgval.function = GDK_INVERT;
            break;
         case kGXorReverse:
            xgval.function = GDK_OR_REVERSE;
            break;
         case kGXcopyInverted:
            xgval.function = GDK_COPY_INVERT;
            break;
         case kGXorInverted:
            xgval.function = GDK_OR_INVERT;
            break;
         case kGXnand:
            xgval.function = GDK_NAND;
            break;
         case kGXset:
            xgval.function = GDK_SET;
            break;
         }
      }
      if (mask & kGCSubwindowMode) {
         xmask |= GDK_GC_SUBWINDOW;
         if (gval.fSubwindowMode == kIncludeInferiors) {
            xgval.subwindow_mode = GDK_INCLUDE_INFERIORS;
         } else {
            xgval.subwindow_mode = GDK_CLIP_BY_CHILDREN;
         }
      }
      if (mask & kGCForeground) {
         xmask |= GDK_GC_FOREGROUND;
         xgval.foreground.pixel = gval.fForeground;
         xgval.foreground.red = GetRValue(gval.fForeground);
         xgval.foreground.green = GetGValue(gval.fForeground);
         xgval.foreground.blue = GetBValue(gval.fForeground);
      }
      if (mask & kGCBackground) {
         xmask |= GDK_GC_BACKGROUND;
         xgval.background.pixel = gval.fBackground;
         xgval.background.red = GetRValue(gval.fBackground);
         xgval.background.green = GetGValue(gval.fBackground);
         xgval.background.blue = GetBValue(gval.fBackground);
      }
      if (mask & kGCLineWidth) {
         xmask |= GDK_GC_LINE_WIDTH;
         xgval.line_width = gval.fLineWidth;
      }
      if (mask & kGCLineStyle) {
         xmask |= GDK_GC_LINE_STYLE;
         xgval.line_style = (GdkLineStyle) gval.fLineStyle; // ident mapping
      }
      if (mask & kGCCapStyle) {
         xmask |= GDK_GC_CAP_STYLE;
         xgval.cap_style = (GdkCapStyle) gval.fCapStyle; // ident mapping
      }
      if (mask & kGCJoinStyle) {
         xmask |= GDK_GC_JOIN_STYLE;
         xgval.join_style = (GdkJoinStyle) gval.fJoinStyle; // ident mapping
      }
      if ((mask & kGCFillStyle)) {
         xmask |= GDK_GC_FILL;
         xgval.fill = (GdkFill) gval.fFillStyle;   // ident mapping
      }
      if ((mask & kGCTile)) {
         xmask |= GDK_GC_TILE;
         xgval.tile = (GdkPixmap *) gval.fTile;
      }
      if ((mask & kGCStipple)) {
         xmask |= GDK_GC_STIPPLE;
         xgval.stipple = (GdkPixmap *) gval.fStipple;
      }
      if ((mask & kGCTileStipXOrigin)) {
         xmask |= GDK_GC_TS_X_ORIGIN;
         xgval.ts_x_origin = gval.fTsXOrigin;
      }
      if ((mask & kGCTileStipYOrigin)) {
         xmask |= GDK_GC_TS_Y_ORIGIN;
         xgval.ts_y_origin = gval.fTsYOrigin;
      }
      if ((mask & kGCFont)) {
         xmask |= GDK_GC_FONT;
         xgval.font = (GdkFont *) gval.fFont;
      }
      if ((mask & kGCGraphicsExposures)) {
         xmask |= GDK_GC_EXPOSURES;
         xgval.graphics_exposures = gval.fGraphicsExposures;
      }
      if ((mask & kGCClipXOrigin)) {
         xmask |= GDK_GC_CLIP_X_ORIGIN;
         xgval.clip_x_origin = gval.fClipXOrigin;
      }
      if ((mask & kGCClipYOrigin)) {
         xmask |= GDK_GC_CLIP_Y_ORIGIN;
         xgval.clip_y_origin = gval.fClipYOrigin;
      }
      if ((mask & kGCClipMask)) {
         xmask |= GDK_GC_CLIP_MASK;
         xgval.clip_mask = (GdkPixmap *) gval.fClipMask;
      }
   } else {
      // map XValues to GCValues_t
      Mask_t mask = 0;

      if ((xmask & GDK_GC_FUNCTION)) {
         mask |= kGCFunction;
         gval.fFunction = (EGraphicsFunction) xgval.function;	// ident mapping
         switch (xgval.function) {
         case GDK_CLEAR:
            gval.fFunction = kGXclear;
            break;
         case GDK_AND:
            gval.fFunction = kGXand;
            break;
         case GDK_AND_REVERSE:
            gval.fFunction = kGXandReverse;
            break;
         case GDK_COPY:
            gval.fFunction = kGXcopy;
            break;
         case GDK_AND_INVERT:
            gval.fFunction = kGXandInverted;
            break;
         case GDK_NOOP:
            gval.fFunction = kGXnoop;
            break;
         case GDK_XOR:
            gval.fFunction = kGXxor;
            break;
         case GDK_OR:
            gval.fFunction = kGXor;
            break;
         case GDK_EQUIV:
            gval.fFunction = kGXequiv;
            break;
         case GDK_INVERT:
            gval.fFunction = kGXinvert;
            break;
         case GDK_OR_REVERSE:
            gval.fFunction = kGXorReverse;
            break;
         case GDK_COPY_INVERT:
            gval.fFunction = kGXcopyInverted;
            break;
         case GDK_OR_INVERT:
            gval.fFunction = kGXorInverted;
            break;
         case GDK_NAND:
            gval.fFunction = kGXnand;
            break;
         case GDK_SET:
            gval.fFunction = kGXset;
            break;
         }
      }
      if (xmask & GDK_GC_SUBWINDOW) {
         mask |= kGCSubwindowMode;
         if (xgval.subwindow_mode == GDK_INCLUDE_INFERIORS)
            gval.fSubwindowMode = kIncludeInferiors;
         else
            gval.fSubwindowMode = kClipByChildren;
      }
      if ((xmask & GDK_GC_FOREGROUND)) {
         mask |= kGCForeground;
         gval.fForeground = xgval.foreground.pixel;
      }
      if ((xmask & GDK_GC_BACKGROUND)) {
         mask |= kGCBackground;
         gval.fBackground = xgval.background.pixel;
      }
      if ((xmask & GDK_GC_LINE_WIDTH)) {
         mask |= kGCLineWidth;
         gval.fLineWidth = xgval.line_width;
      }
      if ((xmask & GDK_GC_LINE_STYLE)) {
         mask |= kGCLineStyle;
         gval.fLineStyle = xgval.line_style;	// ident mapping
      }
      if ((xmask & GDK_GC_CAP_STYLE)) {
         mask |= kGCCapStyle;
         gval.fCapStyle = xgval.cap_style;	// ident mapping
      }
      if ((xmask & GDK_GC_JOIN_STYLE)) {
         mask |= kGCJoinStyle;
         gval.fJoinStyle = xgval.join_style;	// ident mapping
      }
      if ((xmask & GDK_GC_FILL)) {
         mask |= kGCFillStyle;
         gval.fFillStyle = xgval.fill;	// ident mapping
      }
      if ((xmask & GDK_GC_TILE)) {
         mask |= kGCTile;
         gval.fTile = (Pixmap_t) xgval.tile;
      }
      if ((xmask & GDK_GC_STIPPLE)) {
         mask |= kGCStipple;
         gval.fStipple = (Pixmap_t) xgval.stipple;
      }
      if ((xmask & GDK_GC_TS_X_ORIGIN)) {
         mask |= kGCTileStipXOrigin;
         gval.fTsXOrigin = xgval.ts_x_origin;
      }
      if ((xmask & GDK_GC_TS_Y_ORIGIN)) {
         mask |= kGCTileStipYOrigin;
         gval.fTsYOrigin = xgval.ts_y_origin;
      }
      if ((xmask & GDK_GC_FONT)) {
         mask |= kGCFont;
         gval.fFont = (FontH_t) xgval.font;
      }
      if ((xmask & GDK_GC_EXPOSURES)) {
         mask |= kGCGraphicsExposures;
         gval.fGraphicsExposures = (Bool_t) xgval.graphics_exposures;
      }
      if ((xmask & GDK_GC_CLIP_X_ORIGIN)) {
         mask |= kGCClipXOrigin;
         gval.fClipXOrigin = xgval.clip_x_origin;
      }
      if ((xmask & GDK_GC_CLIP_Y_ORIGIN)) {
         mask |= kGCClipYOrigin;
         gval.fClipYOrigin = xgval.clip_y_origin;
      }
      if ((xmask & GDK_GC_CLIP_MASK)) {
         mask |= kGCClipMask;
         gval.fClipMask = (Pixmap_t) xgval.clip_mask;
      }
      gval.fMask = mask;
   }
}

//______________________________________________________________________________
void TGWin32::GetWindowAttributes(Window_t id, WindowAttributes_t & attr)
{
   // Get window attributes and return filled in attributes structure.

   if (!id) return;

   RECT rcClient, rcWind;
   ::GetClientRect((HWND)GDK_DRAWABLE_XID((GdkWindow *) id), &rcClient);
   ::GetWindowRect((HWND)GDK_DRAWABLE_XID((GdkWindow *) id), &rcWind);

   gdk_window_get_geometry((GdkWindow *) id, &attr.fX, &attr.fY,
                           &attr.fWidth, &attr.fHeight, &attr.fDepth);
   attr.fX = ((rcWind.right - rcWind.left) - rcClient.right) / 2;
   attr.fY = ((rcWind.bottom - rcWind.top) - rcClient.bottom) - attr.fX;

   attr.fRoot = (Window_t) GDK_ROOT_PARENT();
   attr.fColormap = (Colormap_t) gdk_window_get_colormap((GdkWindow *) id);
   attr.fBorderWidth = 0;
   attr.fVisual = gdk_window_get_visual((GdkWindow *) id);
   attr.fClass = kInputOutput;
   attr.fBackingStore = kNotUseful;
   attr.fSaveUnder = kFALSE;
   attr.fMapInstalled = kTRUE;
   attr.fOverrideRedirect = kFALSE;   // boolean value for override-redirect

   if (!gdk_window_is_visible((GdkWindow *) id)) {
      attr.fMapState = kIsUnmapped;
   } else if (!gdk_window_is_viewable((GdkWindow *) id)) {
      attr.fMapState = kIsUnviewable;
   } else {
      attr.fMapState = kIsViewable;
   }

   UInt_t tmp_mask = (UInt_t)gdk_window_get_events((GdkWindow *) id);
   UInt_t evmask;
   MapEventMask(evmask, tmp_mask, kFALSE);

   attr.fYourEventMask = evmask;
}

//______________________________________________________________________________
Display_t TGWin32::GetDisplay() const
{
   //

   return 0;
}

//______________________________________________________________________________
Int_t TGWin32::GetDepth() const
{
   // Get maximum number of planes.

   return gdk_visual_get_best_depth();
}

//______________________________________________________________________________
Atom_t TGWin32::InternAtom(const char *atom_name, Bool_t only_if_exist)
{
   // Return atom handle for atom_name. If it does not exist
   // create it if only_if_exist is false. Atoms are used to communicate
   // between different programs (i.e. window manager) via the X server.

   GdkAtom a = gdk_atom_intern((const gchar *) atom_name, only_if_exist);

   if (a == None) return kNone;
   return (Atom_t) a;
}

//______________________________________________________________________________
Window_t TGWin32::GetDefaultRootWindow() const
{
   // Return handle to the default root window created when calling
   // XOpenDisplay().

   return (Window_t) GDK_ROOT_PARENT();
}

//______________________________________________________________________________
Window_t TGWin32::GetParent(Window_t id) const
{
   // Return the parent of the window.

   if (!id) return (Window_t)0;

   return (Window_t)gdk_window_get_parent((GdkWindow *) id);
}

//______________________________________________________________________________
FontStruct_t TGWin32::LoadQueryFont(const char *font_name)
{
   // Load font and query font. If font is not found 0 is returned,
   // otherwise an opaque pointer to the FontStruct_t.
   // Free the loaded font using DeleteFont().

   char  family[100], weight[32], slant[32], fontname[256];
   Int_t n1, pixel, numfields;

   numfields = sscanf(font_name, "%s -%d%n", family, &pixel, &n1);
   if (numfields == 2) {
      sprintf(weight,"medium");
      if (strstr(font_name, "bold"))
         sprintf(weight,"bold");
      sprintf(slant,"r");
      if (strstr(font_name, "italic"))
         sprintf(slant,"i");
      sprintf(fontname, "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-iso8859-1", 
              family, weight, slant, pixel);
   }
   else
      sprintf(fontname, "%s", font_name);
   return (FontStruct_t) gdk_font_load(fontname);
}

//______________________________________________________________________________
FontH_t TGWin32::GetFontHandle(FontStruct_t fs)
{
   // Return handle to font described by font structure.

   if (fs) {
      return (FontH_t)gdk_font_ref((GdkFont *) fs);
   }
   return 0;
}

//______________________________________________________________________________
void TGWin32::DeleteFont(FontStruct_t fs)
{
   // Explicitely delete font structure obtained with LoadQueryFont().

   gdk_font_unref((GdkFont *) fs);
}

//______________________________________________________________________________
GContext_t TGWin32::CreateGC(Drawable_t id, GCValues_t *gval)
{
   // Create a graphics context using the values set in gval (but only for
   // those entries that are in the mask).

   if (!id) return (GContext_t)0;

   GdkGCValues xgval;
   ULong_t xmask = 0;

   if (gval) MapGCValues(*gval, xmask, xgval, kTRUE);

   xgval.subwindow_mode = GDK_CLIP_BY_CHILDREN;	// GDK_INCLUDE_INFERIORS;

   GdkGC *gc = gdk_gc_new_with_values((GdkDrawable *) id,
                                      &xgval, (GdkGCValuesMask)xmask);
   return (GContext_t) gc;
}

//______________________________________________________________________________
void TGWin32::ChangeGC(GContext_t gc, GCValues_t * gval)
{
   // Change entries in an existing graphics context, gc, by values from gval.

   GdkGCValues xgval;
   ULong_t xmask = 0;
   Mask_t mask = 0;

   if (gval) {
      mask = gval->fMask;
      MapGCValues(*gval, xmask, xgval, kTRUE);
   }
   if (mask & kGCForeground) {
      gdk_gc_set_foreground((GdkGC *) gc, &xgval.foreground);
   }
   if (mask & kGCBackground) {
      gdk_gc_set_background((GdkGC *) gc, &xgval.background);
   }
   if (mask & kGCFont) {
      gdk_gc_set_font((GdkGC *) gc, xgval.font);
   }
   if (mask & kGCFunction) {
      gdk_gc_set_function((GdkGC *) gc, xgval.function);
   }
   if (mask & kGCFillStyle) {
      gdk_gc_set_fill((GdkGC *) gc, xgval.fill);
   }
   if (mask & kGCTile) {
      gdk_gc_set_tile((GdkGC *) gc, xgval.tile);
   }
   if (mask & kGCStipple) {
      gdk_gc_set_stipple((GdkGC *) gc, xgval.stipple);
   }
   if ((mask & kGCTileStipXOrigin) || (mask & kGCTileStipYOrigin)) {
      gdk_gc_set_ts_origin((GdkGC *) gc, xgval.ts_x_origin,
                           xgval.ts_y_origin);
   }
   if ((mask & kGCClipXOrigin) || (mask & kGCClipYOrigin)) {
      gdk_gc_set_clip_origin((GdkGC *) gc, xgval.clip_x_origin,
                             xgval.clip_y_origin);
   }
   if (mask & kGCClipMask) {
      gdk_gc_set_clip_mask((GdkGC *) gc, xgval.clip_mask);
   }
   if (mask & kGCGraphicsExposures) {
      gdk_gc_set_exposures((GdkGC *) gc, xgval.graphics_exposures);
   }
   if (mask & kGCLineWidth) {
      gdk_gc_set_values((GdkGC *) gc, &xgval, GDK_GC_LINE_WIDTH);
   }
   if (mask & kGCLineStyle) {
      gdk_gc_set_values((GdkGC *) gc, &xgval, GDK_GC_LINE_STYLE);
   }
   if (mask & kGCCapStyle) {
      gdk_gc_set_values((GdkGC *) gc, &xgval, GDK_GC_CAP_STYLE);
   }
   if (mask & kGCJoinStyle) {
      gdk_gc_set_values((GdkGC *) gc, &xgval, GDK_GC_JOIN_STYLE);
   }
   if (mask & kGCSubwindowMode) {
      gdk_gc_set_subwindow((GdkGC *) gc, xgval.subwindow_mode);
   }
}

//______________________________________________________________________________
void TGWin32::CopyGC(GContext_t org, GContext_t dest, Mask_t mask)
{
   // Copies graphics context from org to dest. Only the values specified
   // in mask are copied. Both org and dest must exist.

   GCValues_t gval;
   GdkGCValues xgval;
   ULong_t xmask;

   if (!mask) {
      // in this case copy all fields
      mask = (Mask_t) - 1;
   }

   gval.fMask = mask;           // only set fMask used to convert to xmask
   MapGCValues(gval, xmask, xgval, kTRUE);

   gdk_gc_copy((GdkGC *) dest, (GdkGC *) org);
}

//______________________________________________________________________________
void TGWin32::DeleteGC(GContext_t gc)
{
   // Explicitely delete a graphics context.

   gdk_gc_unref((GdkGC *) gc);
}

//______________________________________________________________________________
Cursor_t TGWin32::CreateCursor(ECursor cursor)
{
   // Create cursor handle (just return cursor from cursor pool fCursors).

   return (Cursor_t) fCursors[cursor];
}

//______________________________________________________________________________
Pixmap_t TGWin32::CreatePixmap(Drawable_t id, UInt_t w, UInt_t h)
{
   // Creates a pixmap of the width and height you specified
   // and returns a pixmap ID that identifies it.

   GdkWindow *wid = (GdkWindow *)id;
   if (!id) wid =  GDK_ROOT_PARENT();

   return (Pixmap_t) gdk_pixmap_new(wid, w, h, gdk_visual_get_best_depth());
}

//______________________________________________________________________________
Pixmap_t TGWin32::CreatePixmap(Drawable_t id, const char *bitmap,
                               UInt_t width, UInt_t height,
                               ULong_t forecolor, ULong_t backcolor,
                               Int_t depth)
{
   // Create a pixmap from bitmap data. Ones will get foreground color and
   // zeroes background color.

   GdkColor fore, back;
   fore.pixel = forecolor;
   fore.red = GetRValue(forecolor);
   fore.green = GetGValue(forecolor);
   fore.blue = GetBValue(forecolor);

   back.pixel = backcolor;
   back.red = GetRValue(backcolor);
   back.green = GetGValue(backcolor);
   back.blue = GetBValue(backcolor);

   GdkWindow *wid = (GdkWindow *)id;
   if (!id) wid =  GDK_ROOT_PARENT();

   return (Pixmap_t) gdk_pixmap_create_from_data(wid, (char *) bitmap, width,
                                                 height, depth, &fore, &back);
}

//______________________________________________________________________________
Pixmap_t TGWin32::CreateBitmap(Drawable_t id, const char *bitmap,
                               UInt_t width, UInt_t height)
{
   // Create a bitmap (i.e. pixmap with depth 1) from the bitmap data.

   GdkWindow *wid = (GdkWindow *)id;
   if (!id) wid =  GDK_ROOT_PARENT();

   Pixmap_t ret = (Pixmap_t) gdk_bitmap_create_from_data(wid,
                                                 (char *)bitmap, width, height);
   return ret;
}

//______________________________________________________________________________
void TGWin32::DeletePixmap(Pixmap_t pmap)
{
   // Explicitely delete pixmap resource.

   gdk_pixmap_unref((GdkPixmap *) pmap);
}

//______________________________________________________________________________
Bool_t TGWin32::CreatePictureFromFile(Drawable_t id, const char *filename,
                                      Pixmap_t & pict,
                                      Pixmap_t & pict_mask,
                                      PictureAttributes_t & attr)
{
   // Create a picture pixmap from data on file. The picture attributes
   // are used for input and output. Returns kTRUE in case of success,
   // kFALSE otherwise. If mask does not exist it is set to kNone.

   GdkBitmap *gdk_pixmap_mask;
   if (strstr(filename, ".xpm") || strstr(filename, ".XPM")) {
      GdkWindow *wid = (GdkWindow *)id;
      if (!id) wid =  GDK_ROOT_PARENT();

      pict = (Pixmap_t) gdk_pixmap_create_from_xpm(wid, &gdk_pixmap_mask, 0,
                                                filename);
      pict_mask = (Pixmap_t) gdk_pixmap_mask;
   } else if (strstr(filename, ".gif") || strstr(filename, ".GIF")) {
      pict = ReadGIF(0, 0, filename, id);
      pict_mask = kNone;
   }

   gdk_drawable_get_size((GdkPixmap *) pict, (int *) &attr.fWidth,
                         (int *) &attr.fHeight);
   if (pict) {
      return kTRUE;
   }
   if (pict_mask) {
      pict_mask = kNone;
   }
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGWin32::CreatePictureFromData(Drawable_t id, char **data,
                                      Pixmap_t & pict,
                                      Pixmap_t & pict_mask,
                                      PictureAttributes_t & attr)
{
   // Create a pixture pixmap from data. The picture attributes
   // are used for input and output. Returns kTRUE in case of success,
   // kFALSE otherwise. If mask does not exist it is set to kNone.

   GdkBitmap *gdk_pixmap_mask;
   GdkWindow *wid = (GdkWindow *)id;
   if (!id) wid =  GDK_ROOT_PARENT();

   pict = (Pixmap_t) gdk_pixmap_create_from_xpm_d(wid, &gdk_pixmap_mask, 0,
                                                  data);
   pict_mask = (Pixmap_t) gdk_pixmap_mask;

   if (pict) {
      return kTRUE;
   }
   if (pict_mask) {
      pict_mask = kNone;
   }
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGWin32::ReadPictureDataFromFile(const char *filename, char ***ret_data)
{
   // Read picture data from file and store in ret_data. Returns kTRUE in
   // case of success, kFALSE otherwise.

   Bool_t ret = kFALSE;
   GdkPixmap *pxm = gdk_pixmap_create_from_xpm(NULL, NULL, NULL, filename);
   ret_data = 0;

   if (pxm==NULL) return kFALSE;

   HBITMAP hbm = (HBITMAP)GDK_DRAWABLE_XID(pxm);
   BITMAP bitmap;

   ret = ::GetObject(hbm, sizeof(HBITMAP), (LPVOID)&bitmap);
   ret_data = (char ***)&bitmap.bmBits;
   gdk_pixmap_unref(pxm);
   return ret;
}

//______________________________________________________________________________
void TGWin32::DeletePictureData(void *data)
{
   // Delete picture data created by the function ReadPictureDataFromFile.

   free(data);
}

//______________________________________________________________________________
void TGWin32::SetDashes(GContext_t gc, Int_t offset, const char *dash_list,
                        Int_t n)
{
   // Specify a dash pattertn. Offset defines the phase of the pattern.
   // Each element in the dash_list array specifies the length (in pixels)
   // of a segment of the pattern. N defines the length of the list.

   int i;
   gint8 dashes[32];
   for (i = 0; i < n; i++) {
      dashes[i] = (gint8) dash_list[i];
   }
   for (i = n; i < 32; i++) {
      dashes[i] = (gint8) 0;
   }

   gdk_gc_set_dashes((GdkGC *) gc, offset, dashes, n);
}

//______________________________________________________________________________
void TGWin32::MapColorStruct(ColorStruct_t * color, GdkColor & xcolor)
{
   // Map a ColorStruct_t to a XColor structure.

   xcolor.pixel = color->fPixel;
   xcolor.red = color->fRed;
   xcolor.green = color->fGreen;
   xcolor.blue = color->fBlue;
}

//______________________________________________________________________________
Bool_t TGWin32::ParseColor(Colormap_t cmap, const char *cname,
                           ColorStruct_t & color)
{
   // Parse string cname containing color name, like "green" or "#00FF00".
   // It returns a filled in ColorStruct_t. Returns kFALSE in case parsing
   // failed, kTRUE in case of success. On success, the ColorStruct_t
   // fRed, fGreen and fBlue fields are all filled in and the mask is set
   // for all three colors, but fPixel is not set.

   GdkColor xc;

   if (gdk_color_parse((char *)cname, &xc)) {
      color.fPixel = xc.pixel = RGB(xc.red, xc.green, xc.blue);
      color.fRed = xc.red;
      color.fGreen = xc.green;
      color.fBlue = xc.blue;
      return kTRUE;
   }
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TGWin32::AllocColor(Colormap_t cmap, ColorStruct_t & color)
{
   // Find and allocate a color cell according to the color values specified
   // in the ColorStruct_t. If no cell could be allocated it returns kFALSE,
   // otherwise kTRUE.

   int status;
   GdkColor xc;

   xc.red = color.fRed;
   xc.green = color.fGreen;
   xc.blue = color.fBlue;

   status = gdk_colormap_alloc_color((GdkColormap *) cmap, &xc, FALSE, TRUE);
   color.fPixel = xc.pixel;

   return kTRUE;                // status != 0 ? kTRUE : kFALSE;
}

//______________________________________________________________________________
void TGWin32::QueryColor(Colormap_t cmap, ColorStruct_t & color)
{
   // Fill in the primary color components for a specific pixel value.
   // On input fPixel should be set on return the fRed, fGreen and
   // fBlue components will be set.

   GdkColor xc;
   xc.pixel = color.fPixel;

   GdkColorContext *cc = gdk_color_context_new(gdk_visual_get_system(), fColormap);
   gdk_color_context_query_color(cc, &xc);
   gdk_color_context_free(cc);

   color.fPixel = xc.pixel;
   color.fRed = xc.red;
   color.fGreen = xc.green;
   color.fBlue = xc.blue;
}

//______________________________________________________________________________
void TGWin32::FreeColor(Colormap_t cmap, ULong_t pixel)
{
   // Free color cell with specified pixel value.

   // FIXME: to be implemented.
}

//______________________________________________________________________________
Bool_t TGWin32::CheckEvent(Window_t id, EGEventType type, Event_t & ev)
{
   // Check if there is for window "id" an event of type "type". If there
   // is fill in the event structure and return true. If no such event
   // return false.

   if (!id) return kFALSE;

   Event_t tev;
   GdkEvent xev;

   tev.fType = type;
   tev.fWindow = (Window_t) id;
   tev.fTime = 0;
   tev.fX = tev.fY = 0;
   tev.fXRoot = tev.fYRoot = 0;
   tev.fCode = 0;
   tev.fState = 0;
   tev.fWidth = tev.fHeight = 0;
   tev.fCount = 0;
   tev.fSendEvent = kFALSE;
   tev.fHandle = 0;
   tev.fFormat = 0;
   tev.fUser[0] = tev.fUser[1] = tev.fUser[2] = tev.fUser[3] = tev.fUser[4] = 0L;

   TGWin32MainThread::LockMSG();
   MapEvent(tev, xev, kTRUE);
   Bool_t r = gdk_check_typed_window_event((GdkWindow *) id, xev.type, &xev);

   if (r) MapEvent(ev, xev, kFALSE);
   TGWin32MainThread::UnlockMSG();

   return r ? kTRUE : kFALSE;
}

//______________________________________________________________________________
void TGWin32::SendEvent(Window_t id, Event_t * ev)
{
   // Send event ev to window id.

   if (!ev || !id) return;

   TGWin32MainThread::LockMSG();
   GdkEvent xev;
   MapEvent(*ev, xev, kTRUE);
   gdk_event_put(&xev);
   TGWin32MainThread::UnlockMSG();
}

//______________________________________________________________________________
Int_t TGWin32::EventsPending()
{
    // Returns number of pending events.

   Int_t ret;

   TGWin32MainThread::LockMSG();
   ret = (Int_t)gdk_event_queue_find_first();
   TGWin32MainThread::UnlockMSG();

   return ret;
}

//______________________________________________________________________________
void TGWin32::NextEvent(Event_t & event)
{
   // Copies first pending event from event queue to Event_t structure
   // and removes event from queue. Not all of the event fields are valid
   // for each event type, except fType and fWindow.

   TGWin32MainThread::LockMSG();
   GdkEvent *xev = gdk_event_unqueue();

   // fill in Event_t
   event.fType = kOtherEvent;   // bb add
   if (xev == NULL) {
      TGWin32MainThread::UnlockMSG();
      return;
   }
   MapEvent(event, *xev, kFALSE);
   gdk_event_free (xev);
   TGWin32MainThread::UnlockMSG();
}

//______________________________________________________________________________
void TGWin32::MapModifierState(UInt_t & state, UInt_t & xstate, Bool_t tox)
{
   // Map modifier key state to or from X.

   if (tox) {
      xstate = state;
      if (state & kAnyModifier) {
         xstate = GDK_MODIFIER_MASK;
      }
   } else {
      state = xstate;
   }
}

static void _set_event_time(GdkEvent &event, UInt_t time)
{
   // set gdk event time

   switch (event.type) {
      case GDK_MOTION_NOTIFY:
         event.motion.time = time;
      case GDK_BUTTON_PRESS:
      case GDK_2BUTTON_PRESS:
      case GDK_3BUTTON_PRESS:
      case GDK_BUTTON_RELEASE:
      case GDK_SCROLL:
         event.button.time = time;
      case GDK_KEY_PRESS:
      case GDK_KEY_RELEASE:
         event.key.time = time;
      case GDK_ENTER_NOTIFY:
      case GDK_LEAVE_NOTIFY:
         event.crossing.time = time;
      case GDK_PROPERTY_NOTIFY:
         event.property.time = time;
      case GDK_SELECTION_CLEAR:
      case GDK_SELECTION_REQUEST:
      case GDK_SELECTION_NOTIFY:
         event.selection.time = time;
      case GDK_PROXIMITY_IN:
      case GDK_PROXIMITY_OUT:
         event.proximity.time = time;
      case GDK_DRAG_ENTER:
      case GDK_DRAG_LEAVE:
      case GDK_DRAG_MOTION:
      case GDK_DRAG_STATUS:
      case GDK_DROP_START:
      case GDK_DROP_FINISHED:
         event.dnd.time = time;
      default:                 /* use current time */
         break;
   }
}

//______________________________________________________________________________
void TGWin32::MapEvent(Event_t & ev, GdkEvent & xev, Bool_t tox)
{
   // Map Event_t structure to gdk_event structure. If tox is false
   // map the other way.

   if (tox) {
      // map from Event_t to gdk_event
      xev.type = GDK_NOTHING;
      if (ev.fType == kGKeyPress)
         xev.type = GDK_KEY_PRESS;
      if (ev.fType == kKeyRelease)
         xev.type = GDK_KEY_RELEASE;
      if (ev.fType == kButtonPress)
         xev.type = GDK_BUTTON_PRESS;
      if (ev.fType == kButtonRelease)
         xev.type = GDK_BUTTON_RELEASE;
      if (ev.fType == kMotionNotify)
         xev.type = GDK_MOTION_NOTIFY;
      if (ev.fType == kEnterNotify)
         xev.type = GDK_ENTER_NOTIFY;
      if (ev.fType == kLeaveNotify)
         xev.type = GDK_LEAVE_NOTIFY;
      if (ev.fType == kExpose)
         xev.type = GDK_EXPOSE;
      if (ev.fType == kConfigureNotify)
         xev.type = GDK_CONFIGURE;
      if (ev.fType == kMapNotify)
         xev.type = GDK_MAP;
      if (ev.fType == kUnmapNotify)
         xev.type = GDK_UNMAP;
      if (ev.fType == kDestroyNotify)
         xev.type = GDK_DESTROY;
      if (ev.fType == kClientMessage)
         xev.type = GDK_CLIENT_EVENT;
      if (ev.fType == kSelectionClear)
         xev.type = GDK_SELECTION_CLEAR;
      if (ev.fType == kSelectionRequest)
         xev.type = GDK_SELECTION_REQUEST;
      if (ev.fType == kSelectionNotify)
         xev.type = GDK_SELECTION_NOTIFY;

      xev.any.type = xev.type;
      xev.any.send_event = ev.fSendEvent;
      if (ev.fType == kDestroyNotify) {
         xev.any.window = (GdkWindow *) ev.fWindow;
      }
      if (ev.fType == kFocusIn) {
         xev.type = GDK_FOCUS_CHANGE;
         xev.focus_change.type = xev.type;
         xev.focus_change.window = (GdkWindow *) ev.fWindow;
         xev.focus_change.in = TRUE;
      }
      if (ev.fType == kFocusOut) {
         xev.type = GDK_FOCUS_CHANGE;
         xev.focus_change.type = xev.type;
         xev.focus_change.window = (GdkWindow *) ev.fWindow;
         xev.focus_change.in = FALSE;
      }
      if (ev.fType == kGKeyPress || ev.fType == kKeyRelease) {
         xev.key.window = (GdkWindow *) ev.fWindow;
         xev.key.type = xev.type;
         MapModifierState(ev.fState, xev.key.state, kTRUE); // key mask
         xev.key.keyval = ev.fCode; // key code
      }
      if (ev.fType == kButtonPress || ev.fType == kButtonRelease) {
         xev.button.window = (GdkWindow *) ev.fWindow;
         xev.button.type = xev.type;
         xev.button.x = ev.fX;
         xev.button.y = ev.fY;
         xev.button.x_root = ev.fXRoot;
         xev.button.y_root = ev.fYRoot;
         MapModifierState(ev.fState, xev.button.state, kTRUE); // button mask
         xev.button.button = ev.fCode; // button code
      }
      if (ev.fType == kSelectionNotify) {
         xev.selection.window = (GdkWindow *) ev.fUser[0];
         xev.selection.requestor = (guint32) ev.fUser[0];
         xev.selection.selection = (GdkAtom) ev.fUser[1];
         xev.selection.target = (GdkAtom) ev.fUser[2];
         xev.selection.property = (GdkAtom) ev.fUser[3];
         xev.selection.type = xev.type;
      }
      if (ev.fType == kClientMessage) {
         if ((ev.fFormat == 32) && (ev.fHandle == gWM_DELETE_WINDOW)) {
            xev.type = GDK_DELETE;
            xev.any.type = xev.type;
            xev.any.window = (GdkWindow *) ev.fWindow;
         } else {
            xev.client.window = (GdkWindow *) ev.fWindow;
            xev.client.type = xev.type;
            xev.client.message_type = (GdkAtom) ev.fHandle;
            xev.client.data_format = ev.fFormat;
            xev.client.data.l[0] = ev.fUser[0];
            if (sizeof(ev.fUser[0]) > 4) {
               SplitLong(ev.fUser[1], xev.client.data.l[1],
                         xev.client.data.l[3]);
               SplitLong(ev.fUser[2], xev.client.data.l[2],
                         xev.client.data.l[4]);
            } else {
               xev.client.data.l[1] = ev.fUser[1];
               xev.client.data.l[2] = ev.fUser[2];
               xev.client.data.l[3] = ev.fUser[3];
               xev.client.data.l[4] = ev.fUser[4];
            }
         }
      }
      if (ev.fType == kMotionNotify) {
         xev.motion.window = (GdkWindow *) ev.fWindow;
         xev.motion.type = xev.type;
         xev.motion.x = ev.fX;
         xev.motion.y = ev.fY;
         xev.motion.x_root = ev.fXRoot;
         xev.motion.y_root = ev.fYRoot;
      }
      if ((ev.fType == kEnterNotify) || (ev.fType == kLeaveNotify)) {
         xev.crossing.window = (GdkWindow *) ev.fWindow;
         xev.crossing.type = xev.type;
         xev.crossing.x = ev.fX;
         xev.crossing.y = ev.fY;
         xev.crossing.x_root = ev.fXRoot;
         xev.crossing.y_root = ev.fYRoot;
         xev.crossing.mode = (GdkCrossingMode) ev.fCode; // NotifyNormal, NotifyGrab, NotifyUngrab
         MapModifierState(ev.fState, xev.crossing.state, kTRUE);  // key or button mask
      }
      if (ev.fType == kExpose) {
         xev.expose.window = (GdkWindow *) ev.fWindow;
         xev.expose.type = xev.type;
         xev.expose.area.x = ev.fX;
         xev.expose.area.y = ev.fY;
         xev.expose.area.width = ev.fWidth;  // width and
         xev.expose.area.height = ev.fHeight;   // height of exposed area
         xev.expose.count = ev.fCount; // number of expose events still to come
      }
      if (ev.fType == kConfigureNotify) {
         xev.configure.window = (GdkWindow *) ev.fWindow;
         xev.configure.type = xev.type;
         xev.configure.x = ev.fX;
         xev.configure.y = ev.fY;
         xev.configure.width = ev.fWidth;
         xev.configure.height = ev.fHeight;
      }
      if (ev.fType == kSelectionClear) {
         xev.selection.window = (GdkWindow *) ev.fWindow;
         xev.selection.type = xev.type;
         xev.selection.selection = ev.fUser[0];
      }
      if (ev.fType == kSelectionRequest) {
         xev.selection.window = (GdkWindow *) ev.fUser[0];
         xev.selection.type = xev.type;
         xev.selection.selection = ev.fUser[1];
         xev.selection.target = ev.fUser[2];
         xev.selection.property = ev.fUser[3];
      }
      if ((ev.fType == kMapNotify) || (ev.fType == kUnmapNotify)) {
         xev.any.window = (GdkWindow *) ev.fWindow;
      }
      if (xev.type != GDK_CLIENT_EVENT)
         _set_event_time(xev, ev.fTime);
   } else {
      // map from gdk_event to Event_t
      ev.fType = kOtherEvent;
      if (xev.type == GDK_KEY_PRESS)
         ev.fType = kGKeyPress;
      if (xev.type == GDK_KEY_RELEASE)
         ev.fType = kKeyRelease;
      if (xev.type == GDK_BUTTON_PRESS)
         ev.fType = kButtonPress;
      if (xev.type == GDK_BUTTON_RELEASE)
         ev.fType = kButtonRelease;
      if (xev.type == GDK_MOTION_NOTIFY)
         ev.fType = kMotionNotify;
      if (xev.type == GDK_ENTER_NOTIFY)
         ev.fType = kEnterNotify;
      if (xev.type == GDK_LEAVE_NOTIFY)
         ev.fType = kLeaveNotify;
      if (xev.type == GDK_EXPOSE)
         ev.fType = kExpose;
      if (xev.type == GDK_CONFIGURE)
         ev.fType = kConfigureNotify;
      if (xev.type == GDK_MAP)
         ev.fType = kMapNotify;
      if (xev.type == GDK_UNMAP)
         ev.fType = kUnmapNotify;
      if (xev.type == GDK_DESTROY)
         ev.fType = kDestroyNotify;
      if (xev.type == GDK_SELECTION_CLEAR)
         ev.fType = kSelectionClear;
      if (xev.type == GDK_SELECTION_REQUEST)
         ev.fType = kSelectionRequest;
      if (xev.type == GDK_SELECTION_NOTIFY)
         ev.fType = kSelectionNotify;

      ev.fSendEvent = kFALSE; //xev.any.send_event ? kTRUE : kFALSE;
      ev.fTime = gdk_event_get_time((GdkEvent *)&xev);
      ev.fWindow = (Window_t) xev.any.window;

      if ((xev.type == GDK_MAP) || (xev.type == GDK_UNMAP)) {
         ev.fWindow = (Window_t) xev.any.window;
      }
      if (xev.type == GDK_DELETE) {
         ev.fWindow = (Window_t) xev.any.window;
         ev.fType = kClientMessage;
         ev.fFormat = 32;
         ev.fHandle = gWM_DELETE_WINDOW;
         ev.fUser[0] = (Long_t) gWM_DELETE_WINDOW;
         if (sizeof(ev.fUser[0]) > 4) {
            AsmLong(xev.client.data.l[1], xev.client.data.l[3],
                    ev.fUser[1]);
            AsmLong(xev.client.data.l[2], xev.client.data.l[4],
                    ev.fUser[2]);
         } else {
            ev.fUser[1] = 0; //xev.client.data.l[1];
            ev.fUser[2] = 0; //xev.client.data.l[2];
            ev.fUser[3] = 0; //xev.client.data.l[3];
            ev.fUser[4] = 0; //xev.client.data.l[4];
         }
      }
      if (xev.type == GDK_DESTROY) {
         ev.fType = kDestroyNotify;
         ev.fHandle = (Window_t) xev.any.window;   // window to be destroyed
         ev.fWindow = (Window_t) xev.any.window;
      }
      if (xev.type == GDK_FOCUS_CHANGE) {
         ev.fWindow = (Window_t) xev.focus_change.window;
         ev.fCode = kNotifyNormal;
         ev.fState = 0;
         if (xev.focus_change.in == TRUE) {
            ev.fType = kFocusIn;
         } else {
            ev.fType = kFocusOut;
         }
      }
      if (ev.fType == kGKeyPress || ev.fType == kKeyRelease) {
         ev.fWindow = (Window_t) xev.key.window;
         MapModifierState(ev.fState, xev.key.state, kFALSE);   // key mask
         ev.fCode = xev.key.keyval;  // key code
         ev.fUser[1] = xev.key.length;
         if (xev.key.length > 0) ev.fUser[2] = xev.key.string[0];
         if (xev.key.length > 1) ev.fUser[3] = xev.key.string[1];
         if (xev.key.length > 2) ev.fUser[4] = xev.key.string[2];
         HWND tmpwin = (HWND) GetWindow((HWND) GDK_DRAWABLE_XID((GdkWindow *)xev.key.window), GW_CHILD);
         if (tmpwin) {
            ev.fUser[0] = (ULong_t) gdk_xid_table_lookup((HANDLE)tmpwin);
         } else {
            ev.fUser[0] = (ULong_t) xev.key.window;
         }
      }
      if (ev.fType == kButtonPress || ev.fType == kButtonRelease) {
         ev.fWindow = (Window_t) xev.button.window;
         ev.fX = xev.button.x;
         ev.fY = xev.button.y;
         ev.fXRoot = xev.button.x_root;
         ev.fYRoot = xev.button.y_root;
         MapModifierState(ev.fState, xev.button.state, kFALSE);   // button mask
         ev.fCode = xev.button.button; // button code
         POINT tpoint;
         tpoint.x = xev.button.x;
         tpoint.y = xev.button.y;
         HWND tmpwin = ChildWindowFromPoint((HWND) GDK_DRAWABLE_XID((GdkWindow *)xev.button.window), tpoint);
         if (tmpwin) {
             ev.fUser[0] = (ULong_t) gdk_xid_table_lookup((HANDLE)tmpwin);
         } else {
            ev.fUser[0] = (ULong_t) 0;
         }
      }
      if (ev.fType == kMotionNotify) {
         ev.fWindow = (Window_t) xev.motion.window;
         ev.fX = xev.motion.x;
         ev.fY = xev.motion.y;
         ev.fXRoot = xev.motion.x_root;
         ev.fYRoot = xev.motion.y_root;
         MapModifierState(ev.fState, xev.motion.state, kFALSE);   // key or button mask

         POINT tpoint;
         tpoint.x = xev.button.x;
         tpoint.y = xev.button.y;
         HWND tmpwin = ChildWindowFromPoint((HWND) GDK_DRAWABLE_XID((GdkWindow *)xev.motion.window), tpoint);
         if (tmpwin) {
             ev.fUser[0] = (ULong_t)gdk_xid_table_lookup((HANDLE)tmpwin);
         } else {
            ev.fUser[0] = (ULong_t) xev.motion.window;
         }
      }
      if (ev.fType == kEnterNotify || ev.fType == kLeaveNotify) {
         ev.fWindow = (Window_t) xev.crossing.window;
         ev.fX = xev.crossing.x;
         ev.fY = xev.crossing.y;
         ev.fXRoot = xev.crossing.x_root;
         ev.fYRoot = xev.crossing.y_root;
         ev.fCode = xev.crossing.mode; // NotifyNormal, NotifyGrab, NotifyUngrab
         MapModifierState(ev.fState, xev.crossing.state, kFALSE); // key or button mask
      }
      if (ev.fType == kExpose) {
         ev.fWindow = (Window_t) xev.expose.window;
         ev.fX = xev.expose.area.x;
         ev.fY = xev.expose.area.y;
         ev.fWidth = xev.expose.area.width;  // width and
         ev.fHeight = xev.expose.area.height;   // height of exposed area
         ev.fCount = xev.expose.count; // number of expose events still to come
      }
      if (ev.fType == kConfigureNotify) {
         ev.fWindow = (Window_t) xev.configure.window;
         ev.fX = xev.configure.x;
         ev.fY = xev.configure.y;
         ev.fWidth = xev.configure.width;
         ev.fHeight = xev.configure.height;
      }
      if (xev.type == GDK_CLIENT_EVENT) {
         ev.fWindow = (Window_t) xev.client.window;
         ev.fType = kClientMessage;
         ev.fHandle = xev.client.message_type;
         ev.fFormat = xev.client.data_format;
         ev.fUser[0] = xev.client.data.l[0];
         if (sizeof(ev.fUser[0]) > 4) {
            AsmLong(xev.client.data.l[1], xev.client.data.l[3],
                    ev.fUser[1]);
            AsmLong(xev.client.data.l[2], xev.client.data.l[4],
                    ev.fUser[2]);
         } else {
            ev.fUser[1] = xev.client.data.l[1];
            ev.fUser[2] = xev.client.data.l[2];
            ev.fUser[3] = xev.client.data.l[3];
            ev.fUser[4] = xev.client.data.l[4];
         }
      }
      if (ev.fType == kSelectionClear) {
         ev.fWindow = (Window_t) xev.selection.window;
         ev.fUser[0] = xev.selection.selection;
      }
      if (ev.fType == kSelectionRequest) {
         ev.fWindow = (Window_t) xev.selection.window;
         ev.fUser[0] = (ULong_t) xev.selection.window;
         ev.fUser[1] = xev.selection.selection;
         ev.fUser[2] = xev.selection.target;
         ev.fUser[3] = xev.selection.property;
      }
      if (ev.fType == kSelectionNotify) {
         ev.fWindow = (Window_t) xev.selection.window;
         ev.fUser[0] = (ULong_t) xev.selection.window;
         ev.fUser[1] = xev.selection.selection;
         ev.fUser[2] = xev.selection.target;
         ev.fUser[3] = xev.selection.property;
      }
      if (xev.type == GDK_SCROLL) {
         ev.fType = kButtonRelease;
         if (xev.scroll.direction == GDK_SCROLL_UP) {
            ev.fCode = kButton4;
         } else if (xev.scroll.direction == GDK_SCROLL_DOWN) {
            ev.fCode = kButton5;
         }
         ev.fWindow = (Window_t) xev.scroll.window;
         ev.fX = xev.scroll.x;
         ev.fY = xev.scroll.y;
         ev.fXRoot = xev.scroll.x_root;
         ev.fYRoot = xev.scroll.y_root;
         POINT tpoint;
         tpoint.x = xev.scroll.x;
         tpoint.y = xev.scroll.y;
         HWND tmpwin = ChildWindowFromPoint((HWND) GDK_DRAWABLE_XID((GdkWindow *)xev.scroll.window), tpoint);
         if (tmpwin) {
             ev.fUser[0] = (ULong_t)gdk_xid_table_lookup((HANDLE)tmpwin);
         } else {
            ev.fUser[0] = (ULong_t) 0;
         }
      }
   }
}

//______________________________________________________________________________
void TGWin32::Bell(Int_t percent)
{
   //

   gSystem->Beep();
}

//______________________________________________________________________________
void TGWin32::CopyArea(Drawable_t src, Drawable_t dest, GContext_t gc,
                       Int_t src_x, Int_t src_y, UInt_t width,
                       UInt_t height, Int_t dest_x, Int_t dest_y)
{
   // Copy a drawable (i.e. pixmap) to another drawable (pixmap, window).
   // The graphics context gc will be used and the source will be copied
   // from src_x,src_y,src_x+width,src_y+height to dest_x,dest_y.

   if (!src || !dest) return;

   gdk_window_copy_area((GdkDrawable *) dest, (GdkGC *) gc, dest_x, dest_y,
                        (GdkDrawable *) src, src_x, src_y, width, height);
}

//______________________________________________________________________________
void TGWin32::ChangeWindowAttributes(Window_t id, SetWindowAttributes_t * attr)
{
   // Change window attributes.

   if (!id) return;

   GdkColor color;
   UInt_t xevmask;
   Mask_t evmask;

   if (attr && (attr->fMask & kWAEventMask)) {
      evmask = (Mask_t) attr->fEventMask;
      MapEventMask(evmask, xevmask);
      gdk_window_set_events((GdkWindow *) id, (GdkEventMask) xevmask);
   }
   if (attr && (attr->fMask & kWABackPixel)) {
      color.pixel = attr->fBackgroundPixel;
      color.red = GetRValue(attr->fBackgroundPixel);
      color.green = GetGValue(attr->fBackgroundPixel);
      color.blue = GetBValue(attr->fBackgroundPixel);
      gdk_window_set_background((GdkWindow *) id, &color);
   }
//   if (attr && (attr->fMask & kWAOverrideRedirect))
//      gdk_window_set_override_redirect ((GdkWindow *) id, attr->fOverrideRedirect);
   if (attr && (attr->fMask & kWABackPixmap)) {
      gdk_window_set_back_pixmap((GdkWindow *) id,
                                 (GdkPixmap *) attr->fBackgroundPixmap, 0);
   }
   if (attr && (attr->fMask & kWACursor)) {
      gdk_window_set_cursor((GdkWindow *) id, (GdkCursor *) attr->fCursor);
   }
   if (attr && (attr->fMask & kWAColormap)) {
      gdk_window_set_colormap((GdkWindow *) id,(GdkColormap *) attr->fColormap);
   }
   if (attr && (attr->fMask & kWABorderWidth)) {
      if (attr->fBorderWidth > 0) {
         gdk_window_set_decorations((GdkWindow *) id,
                                    (GdkWMDecoration) GDK_DECOR_BORDER);
      }
   }
}

//______________________________________________________________________________
void TGWin32::ChangeProperty(Window_t id, Atom_t property, Atom_t type,
                             UChar_t * data, Int_t len)
{
   // This function alters the property for the specified window and
   // causes the X server to generate a PropertyNotify event on that
   // window.

   if (!id) return;

   gdk_property_change((GdkWindow *) id, (GdkAtom) property,
                       (GdkAtom) type, 8, GDK_PROP_MODE_REPLACE, data,len);
}

//______________________________________________________________________________
void TGWin32::DrawLine(Drawable_t id, GContext_t gc, Int_t x1, Int_t y1,
                       Int_t x2, Int_t y2)
{
   // Draw a line.

   if (!id) return;

   gdk_draw_line((GdkDrawable *) id, (GdkGC *) gc, x1, y1, x2, y2);
}

//______________________________________________________________________________
void TGWin32::ClearArea(Window_t id, Int_t x, Int_t y, UInt_t w, UInt_t h)
{
   // Clear a window area to the bakcground color.

   if (!id) return;

   gdk_window_clear_area((GdkWindow *) id, x, y, w, h);
}

//______________________________________________________________________________
void TGWin32::WMDeleteNotify(Window_t id)
{
   // Tell WM to send message when window is closed via WM.

   if (!id) return;

   Atom prop;
   prop = (Atom_t) gdk_atom_intern("WM_DELETE_WINDOW", FALSE);

   W32ChangeProperty((HWND) GDK_DRAWABLE_XID((GdkWindow *) id),
                     prop, XA_ATOM, 32, GDK_PROP_MODE_REPLACE,
                     (unsigned char *) &gWM_DELETE_WINDOW, 1);
}

//______________________________________________________________________________
void TGWin32::SetKeyAutoRepeat(Bool_t on)
{
   // Turn key auto repeat on or off.

   if (on) {
      gdk_key_repeat_restore();
    } else {
      gdk_key_repeat_disable();
   }
}

//______________________________________________________________________________
void TGWin32::GrabKey(Window_t id, Int_t keycode, UInt_t modifier, Bool_t grab)
{
   // Establish passive grab on a certain key. That is, when a certain key
   // keycode is hit while certain modifier's (Shift, Control, Meta, Alt)
   // are active then the keyboard will be grabed for window id.
   // When grab is false, ungrab the keyboard for this key and modifier.

   UInt_t xmod;

   MapModifierState(modifier, xmod);

   if (grab) {
      gdk_key_grab(keycode, (GdkEventMask)xmod, (GdkWindow *)id);
   } else {
      gdk_key_ungrab(keycode, (GdkEventMask)xmod, (GdkWindow *)id);
   }
}

//______________________________________________________________________________
void TGWin32::GrabButton(Window_t id, EMouseButton button, UInt_t modifier,
                         UInt_t evmask, Window_t confine, Cursor_t cursor,
                         Bool_t grab)
{
   // Establish passive grab on a certain mouse button. That is, when a
   // certain mouse button is hit while certain modifier's (Shift, Control,
   // Meta, Alt) are active then the mouse will be grabed for window id.
   // When grab is false, ungrab the mouse button for this button and modifier.

   UInt_t xevmask;
   UInt_t xmod;

   if (!id) return;

   MapModifierState(modifier, xmod);

   if (grab) {
      MapEventMask(evmask, xevmask);
      gdk_button_grab(button, xmod, ( GdkWindow *)id, 1,  (GdkEventMask)xevmask,
                      (GdkWindow*)confine,  (GdkCursor*)cursor);
   } else {
      gdk_button_ungrab(button, xmod, ( GdkWindow *)id);
   }
}

//______________________________________________________________________________
void TGWin32::GrabPointer(Window_t id, UInt_t evmask, Window_t confine,
                          Cursor_t cursor, Bool_t grab, Bool_t owner_events)
{
   // Establish an active pointer grab. While an active pointer grab is in
   // effect, further pointer events are only reported to the grabbing
   // client window.

   UInt_t xevmask;
   MapEventMask(evmask, xevmask);

   if (grab) {
      if(!::IsWindowVisible((HWND)GDK_DRAWABLE_XID(id))) return;
      gdk_pointer_grab((GdkWindow *) id, owner_events, (GdkEventMask) xevmask,
                       (GdkWindow *) confine, (GdkCursor *) cursor,
                       GDK_CURRENT_TIME);
   } else {
      gdk_pointer_ungrab(GDK_CURRENT_TIME);
      ::SetCursor((HCURSOR)GDK_CURSOR_XID(fCursors[kPointer]));
   }
}

//______________________________________________________________________________
void TGWin32::SetWindowName(Window_t id, char *name)
{
   // Set window name.

   if (!id) return;

   gdk_window_set_title((GdkWindow *) id, name);
}

//______________________________________________________________________________
void TGWin32::SetIconName(Window_t id, char *name)
{
   // Set window icon name.

   if (!id) return;

   gdk_window_set_icon_name((GdkWindow *) id, name);
}

//______________________________________________________________________________
void TGWin32::SetIconPixmap(Window_t id, Pixmap_t pic)
{
   // Set pixmap the WM can use when the window is iconized.

   if (!id) return;

   gdk_window_set_icon((GdkWindow *)id, NULL, (GdkPixmap *)pic, (GdkPixmap *)pic);
}

#define safestrlen(s) ((s) ? strlen(s) : 0)

//______________________________________________________________________________
void TGWin32::SetClassHints(Window_t id, char *className, char *resourceName)
{
   // Set the windows class and resource name.

   if (!id) return;

   char *class_string;
   char *s;
   int len_nm, len_cl;
   GdkAtom prop;

   prop = gdk_atom_intern("WM_CLASS", kFALSE);

   len_nm = safestrlen(resourceName);
   len_cl = safestrlen(className);

   if ((class_string = s =
        (char *) malloc((unsigned) (len_nm + len_cl + 2)))) {
      if (len_nm) {
         strcpy(s, resourceName);
         s += len_nm + 1;
      } else
         *s++ = '\0';
      if (len_cl) {
         strcpy(s, className);
      } else {
         *s = '\0';
      }

      W32ChangeProperty((HWND) GDK_DRAWABLE_XID((GdkWindow *) id),
                            (Atom) XA_WM_CLASS, (Atom) XA_WM_CLASS, 8,
                            GDK_PROP_MODE_REPLACE,
                            (unsigned char *) class_string,
                            len_nm + len_cl + 2);
      free(class_string);
   }
}

//______________________________________________________________________________
void TGWin32::SetMWMHints(Window_t id, UInt_t value, UInt_t funcs,
                          UInt_t input)
{
   // Set decoration style for MWM-compatible wm (mwm, ncdwm, fvwm?).

   if (!id) return;

   gdk_window_set_decorations((GdkDrawable *) id, (GdkWMDecoration) value);
   gdk_window_set_functions((GdkDrawable *) id, (GdkWMFunction) funcs);
}

//______________________________________________________________________________
void TGWin32::SetWMPosition(Window_t id, Int_t x, Int_t y)
{
   //

   if (!id) return;

   gdk_window_move((GdkDrawable *) id, x, y);
}

//______________________________________________________________________________
void TGWin32::SetWMSize(Window_t id, UInt_t w, UInt_t h)
{
   //

   if (!id) return;

   gdk_window_resize((GdkWindow *) id, w, h);
}

//______________________________________________________________________________
void TGWin32::SetWMSizeHints(Window_t id, UInt_t wmin, UInt_t hmin,
                             UInt_t wmax, UInt_t hmax,
                             UInt_t winc, UInt_t hinc)
{
   // Give the window manager minimum and maximum size hints. Also
   // specify via winc and hinc the resize increments.

   if (!id) return;

   GdkGeometry hints;
   GdkWindowHints flags;

   flags = (GdkWindowHints) (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE |
                             GDK_HINT_RESIZE_INC);
   hints.min_width = (Int_t) wmin;
   hints.max_width = (Int_t) wmax;
   hints.min_height = (Int_t) hmin;
   hints.max_height = (Int_t) hmax;
   hints.width_inc = (Int_t) winc;
   hints.height_inc = (Int_t) hinc;

   gdk_window_set_geometry_hints((GdkWindow *) id, (GdkGeometry *) &hints,
                                 (GdkWindowHints) flags);
}

//______________________________________________________________________________
void TGWin32::SetWMState(Window_t id, EInitialState state)
{
   // Set the initial state of the window. Either kNormalState or kIconicState.

   if (!id) return;

#if 0
   XWMHints hints;
   Int_t xstate = NormalState;

   if (state == kNormalState)
      xstate = NormalState;
   if (state == kIconicState)
      xstate = IconicState;

   hints.flags = StateHint;
   hints.initial_state = xstate;

   XSetWMHints((GdkWindow *) id, &hints);
#endif
}

//______________________________________________________________________________
void TGWin32::SetWMTransientHint(Window_t id, Window_t main_id)
{
   // Tell window manager that window is a transient window of gdk_parent_root.

   if (!id) return;

   gdk_window_set_transient_for((GdkWindow *) id, (GdkWindow *) main_id);
}

//______________________________________________________________________________
void TGWin32::DrawString(Drawable_t id, GContext_t gc, Int_t x, Int_t y,
                         const char *s, Int_t len)
{
   // Draw a string using a specific graphics context in position (x,y).

   if (!id) return;

   GdkGCValues values;
   gdk_gc_get_values((GdkGC *) gc, &values);
   gdk_win32_draw_text((GdkDrawable *) id, (GdkFont *) values.font,
                 (GdkGC *) gc, x, y, (const gchar *)s, len);
}

//______________________________________________________________________________
Int_t TGWin32::TextWidth(FontStruct_t font, const char *s, Int_t len)
{
   // Return length of string in pixels. Size depends on font.

   return gdk_text_width((GdkFont *)font, s, len);
}

//______________________________________________________________________________
void TGWin32::GetFontProperties(FontStruct_t font, Int_t & max_ascent,
                                Int_t & max_descent)
{
   // Return some font properties.

   GdkFont *f = (GdkFont *) font;
   max_ascent = f->ascent;
   max_descent = f->descent;
}

//______________________________________________________________________________
void TGWin32::GetGCValues(GContext_t gc, GCValues_t & gval)
{
   // Get current values from graphics context gc. Which values of the
   // context to get is encoded in the GCValues::fMask member.

   GdkGCValues xgval;
   ULong_t xmask;

   MapGCValues(gval, xmask, xgval, kTRUE);
   gdk_gc_get_values((GdkGC *) gc, &xgval);
   MapGCValues(gval, xmask, xgval, kFALSE);
}

//______________________________________________________________________________
FontStruct_t TGWin32::GetFontStruct(FontH_t fh)
{
   // Retrieve associated font structure once we have the font handle.
   // Free returned FontStruct_t using FreeFontStruct().

   return (FontStruct_t) gdk_font_ref((GdkFont *) fh);
}

//______________________________________________________________________________
void TGWin32::FreeFontStruct(FontStruct_t fs)
{
   // Free font structure returned by GetFontStruct().

   gdk_font_unref((GdkFont *) fs);
}

//______________________________________________________________________________
void TGWin32::ClearWindow(Window_t id)
{
   // Clear window.

   if (!id) return;

   gdk_window_clear((GdkDrawable *) id);
}

//______________________________________________________________________________
Int_t TGWin32::KeysymToKeycode(UInt_t keysym)
{
   // Convert a keysym to the appropriate keycode. For example keysym is
   // a letter and keycode is the matching keyboard key (which is dependend
   // on the current keyboard mapping).

   UInt_t xkeysym;
   MapKeySym(keysym, xkeysym);
   return xkeysym;
}

//______________________________________________________________________________
void TGWin32::FillRectangle(Drawable_t id, GContext_t gc, Int_t x, Int_t y,
                            UInt_t w, UInt_t h)
{
   // Draw a filled rectangle. Filling is done according to the gc.

   if (!id) return;

   gdk_win32_draw_rectangle((GdkDrawable *) id, (GdkGC *) gc, kTRUE, x, y, w, h);
}

//______________________________________________________________________________
void TGWin32::DrawRectangle(Drawable_t id, GContext_t gc, Int_t x, Int_t y,
                            UInt_t w, UInt_t h)
{
   // Draw a rectangle outline.

   if (!id) return;

   gdk_win32_draw_rectangle((GdkDrawable *) id, (GdkGC *) gc, kFALSE, x, y, w, h);
}

//______________________________________________________________________________
void TGWin32::DrawSegments(Drawable_t id, GContext_t gc, Segment_t * seg,
                           Int_t nseg)
{
   // Draws multiple line segments. Each line is specified by a pair of points.

   if (!id) return;

   gdk_win32_draw_segments((GdkDrawable *) id, (GdkGC *) gc, (GdkSegment *)seg, nseg);
}

//______________________________________________________________________________
void TGWin32::SelectInput(Window_t id, UInt_t evmask)
{
   // Defines which input events the window is interested in. By default
   // events are propageted up the window stack. This mask can also be
   // set at window creation time via the SetWindowAttributes_t::fEventMask
   // attribute.

   if (!id) return;

   UInt_t xevmask;
   MapEventMask(evmask, xevmask, kTRUE);
   gdk_window_set_events((GdkWindow *) id, (GdkEventMask)xevmask);
}

//______________________________________________________________________________
Window_t TGWin32::GetInputFocus()
{
   // Returns the window id of the window having the input focus.

   HWND hwnd = ::GetFocus();
   return (Window_t) gdk_xid_table_lookup(hwnd);
}

//______________________________________________________________________________
void TGWin32::SetInputFocus(Window_t id)
{
   // Set keyboard input focus to window id.

   if (!id) return;

   HWND hwnd = (HWND)GDK_DRAWABLE_XID((GdkWindow *)id);
   ::SetFocus(hwnd);
}

//______________________________________________________________________________
Window_t TGWin32::GetPrimarySelectionOwner()
{
   // Returns the window id of the current owner of the primary selection.
   // That is the window in which, for example some text is selected.

   return (Window_t)gdk_selection_owner_get(gClipboardAtom);
}

//______________________________________________________________________________
void TGWin32::SetPrimarySelectionOwner(Window_t id)
{
   // Makes the window id the current owner of the primary selection.
   // That is the window in which, for example some text is selected.

   if (!id) return;

   gdk_selection_owner_set((GdkWindow *) id, gClipboardAtom, GDK_CURRENT_TIME, 0);
}

//______________________________________________________________________________
void TGWin32::ConvertPrimarySelection(Window_t id, Atom_t clipboard, Time_t when)
{
   // XConvertSelection() causes a SelectionRequest event to be sent to the
   // current primary selection owner. This event specifies the selection
   // property (primary selection), the format into which to convert that
   // data before storing it (target = XA_STRING), the property in which
   // the owner will place the information (sel_property), the window that
   // wants the information (id), and the time of the conversion request
   // (when).
   // The selection owner responds by sending a SelectionNotify event, which
   // confirms the selected atom and type.

   if (!id) return;

   gdk_selection_convert((GdkWindow *) id, clipboard,
                         gdk_atom_intern("GDK_TARGET_STRING", 0), when);
}

//______________________________________________________________________________
void TGWin32::LookupString(Event_t * event, char *buf, Int_t buflen,
                           UInt_t & keysym)
{
   // Convert the keycode from the event structure to a key symbol (according
   // to the modifiers specified in the event structure and the current
   // keyboard mapping). In buf a null terminated ASCII string is returned
   // representing the string that is currently mapped to the key code.

   _lookup_string(event, buf, buflen);
   UInt_t ks, xks = (UInt_t) event->fCode;
   MapKeySym(ks, xks, kFALSE);
   keysym = (Int_t) ks;
}

//______________________________________________________________________________
void TGWin32::MapKeySym(UInt_t & keysym, UInt_t & xkeysym, Bool_t tox)
{
   // Map to and from X key symbols. Keysym are the values returned by
   // XLookUpString.

   if (tox) {
      xkeysym = GDK_VoidSymbol;
      if (keysym < 127) {
         xkeysym = keysym;
      } else if (keysym >= kKey_F1 && keysym <= kKey_F35) {
         xkeysym = GDK_F1 + (keysym - (UInt_t) kKey_F1);	// function keys
      } else {
         for (int i = 0; gKeyMap[i].fKeySym; i++) {	// any other keys
            if (keysym == (UInt_t) gKeyMap[i].fKeySym) {
               xkeysym = (UInt_t) gKeyMap[i].fXKeySym;
               break;
            }
         }
      }
   } else {
      keysym = kKey_Unknown;
      // commentary in X11/keysymdef says that X codes match ASCII
      if (xkeysym < 127) {
         keysym = xkeysym;
      } else if (xkeysym >= GDK_F1 && xkeysym <= GDK_F35) {
         keysym = kKey_F1 + (xkeysym - GDK_F1);	// function keys
      } else if (xkeysym >= GDK_KP_0 && xkeysym <= GDK_KP_9) {
         keysym = kKey_0 + (xkeysym - GDK_KP_0);	// numeric keypad keys
      } else {
         for (int i = 0; gKeyMap[i].fXKeySym; i++) {	// any other keys
            if (xkeysym == gKeyMap[i].fXKeySym) {
               keysym = (UInt_t) gKeyMap[i].fKeySym;
               break;
            }
         }
      }
   }
}

//______________________________________________________________________________
void TGWin32::GetPasteBuffer(Window_t id, Atom_t atom, TString & text,
                             Int_t & nchar, Bool_t del)
{
   // Get contents of paste buffer atom into string. If del is true delete
   // the paste buffer afterwards.

   if (!id) return;

   char *data;
   int nread, actual_format;

   nread = gdk_selection_property_get((GdkWindow *) id,
                                      (unsigned char **) &data,
                                      (GdkAtom *) & atom, &actual_format);

   if ((nread == 0) || (data == NULL)) {
      nchar = 0;
      return;
   }

   text.Insert(0, (const char *) data);
   nchar = 1;                   //strlen(data);
   g_free(data);

   // if (del)
   gdk_property_delete((GdkWindow *) id,
                       gdk_atom_intern("GDK_SELECTION", FALSE));
}

//______________________________________________________________________________
void TGWin32::TranslateCoordinates(Window_t src, Window_t dest,
                                   Int_t src_x, Int_t src_y,
                                   Int_t &dest_x, Int_t &dest_y,
                                   Window_t &child)
{
   // TranslateCoordinates translates coordinates from the frame of
   // reference of one window to another. If the point is contained
   // in a mapped child of the destination, the id of that child is
   // returned as well.

   if (!src || !dest) return;

   HWND sw, dw, ch = NULL;
   POINT point;
   sw = (HWND)GDK_DRAWABLE_XID((GdkWindow *)src);
   dw = (HWND)GDK_DRAWABLE_XID((GdkWindow *)dest);
   point.x = src_x;
   point.y = src_y;
   ::MapWindowPoints(sw,        // handle of window to be mapped from
                   dw,          // handle to window to be mapped to
                   &point,      // pointer to array with points to map
                   1);          // number of structures in array
   ch = ::ChildWindowFromPointEx(dw, point, CWP_SKIPDISABLED | CWP_SKIPINVISIBLE);
   child = (Window_t)gdk_xid_table_lookup(ch);

   if (child == src) {
      child = (Window_t) 0;
   }
   dest_x = point.x;
   dest_y = point.y;
}

//______________________________________________________________________________
void TGWin32::GetWindowSize(Drawable_t id, Int_t & x, Int_t & y,
                            UInt_t & w, UInt_t & h)
{
   // Return geometry of window (should be called GetGeometry but signature
   // already used).

   if (!id) return;

   Int_t ddum;
   if (GDK_DRAWABLE_TYPE(id) == GDK_DRAWABLE_PIXMAP) {
      x = y = 0;
      gdk_drawable_get_size((GdkDrawable *)id, (int*)&w, (int*)&h);
   }
   else {
      gdk_window_get_geometry((GdkDrawable *) id, &x, &y, (int*)&w,
                              (int*)&h, &ddum);
   }
}

//______________________________________________________________________________
void TGWin32::FillPolygon(Window_t id, GContext_t gc, Point_t * points,
                          Int_t npnt)
{
   // FillPolygon fills the region closed by the specified path.
   // The path is closed automatically if the last point in the list does
   // not coincide with the first point. All point coordinates are
   // treated as relative to the origin. For every pair of points
   // inside the polygon, the line segment connecting them does not
   // intersect the path.

   if (!id) return;

   gdk_win32_draw_polygon((GdkWindow *) id, (GdkGC *) gc, 1, (GdkPoint *) points, npnt);
}

//______________________________________________________________________________
void TGWin32::QueryPointer(Window_t id, Window_t &rootw,
                           Window_t &childw, Int_t &root_x,
                           Int_t &root_y, Int_t &win_x, Int_t &win_y,
                           UInt_t &mask)
{
   // Returns the root window the pointer is logically on and the pointer
   // coordinates relative to the root window's origin.
   // The pointer coordinates returned to win_x and win_y are relative to
   // the origin of the specified window. In this case, QueryPointer returns
   // the child that contains the pointer, if any, or else kNone to
   // childw. QueryPointer returns the current logical state of the
   // keyboard buttons and the modifier keys in mask.

   if (!id) return;

   POINT currPt;
   HWND chw, window;
   UInt_t umask = 0;
   BYTE kbd[256];

   window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)id);
   rootw = (Window_t)GDK_ROOT_PARENT();
   ::GetCursorPos(&currPt);
   chw = ::WindowFromPoint(currPt);
   childw = (Window_t)gdk_xid_table_lookup(chw);
   root_x = currPt.x;
   root_y = currPt.y;

   ::ScreenToClient(window, &currPt);
   win_x = currPt.x;
   win_y = currPt.y;

   ::GetKeyboardState (kbd);

   if (kbd[VK_SHIFT] & 0x80) {
      umask |= GDK_SHIFT_MASK;
   }
   if (kbd[VK_CAPITAL] & 0x80) {
      umask |= GDK_LOCK_MASK;
   }
   if (kbd[VK_CONTROL] & 0x80) {
      umask |= GDK_CONTROL_MASK;
   }
   if (kbd[VK_MENU] & 0x80) {
      umask |= GDK_MOD1_MASK;
   }
   if (kbd[VK_LBUTTON] & 0x80) {
      umask |= GDK_BUTTON1_MASK;
   }
   if (kbd[VK_MBUTTON] & 0x80) {
      umask |= GDK_BUTTON2_MASK;
   }
   if (kbd[VK_RBUTTON] & 0x80) {
      umask |= GDK_BUTTON3_MASK;
   }

   MapModifierState(mask, umask, kFALSE);
}

//______________________________________________________________________________
void TGWin32::SetForeground(GContext_t gc, ULong_t foreground)
{
   // Set foreground color in graphics context (shortcut for ChangeGC with
   // only foreground mask set).

   GdkColor fore;
   fore.pixel = foreground;
   fore.red = GetRValue(foreground);
   fore.green = GetGValue(foreground);
   fore.blue = GetBValue(foreground);
   gdk_gc_set_foreground((GdkGC *) gc, &fore);
}

//______________________________________________________________________________
void TGWin32::SetClipRectangles(GContext_t gc, Int_t x, Int_t y,
                                Rectangle_t * recs, Int_t n)
{
   // Set clipping rectangles in graphics context. X, Y specify the origin
   // of the rectangles. Recs specifies an array of rectangles that define
   // the clipping mask and n is the number of rectangles.

   Int_t i;
   GdkRectangle *grects = new GdkRectangle[n];

   for (i = 0; i < n; i++) {
      grects[i].x = x+recs[i].fX;
      grects[i].y = y+recs[i].fY;
      grects[i].width = recs[i].fWidth;
      grects[i].height = recs[i].fHeight;
   }

   for (i = 0; i < n; i++) {
      gdk_gc_set_clip_rectangle((GdkGC *)gc, (GdkRectangle*)recs);
   }
   delete [] grects;
}

//______________________________________________________________________________
void TGWin32::Update(Int_t mode)
{
   // Flush (mode = 0, default) or synchronize (mode = 1) X output buffer.
   // Flush flushes output buffer. Sync flushes buffer and waits till all
   // requests have been processed by X server.

   GdiFlush();
}

//______________________________________________________________________________
Region_t TGWin32::CreateRegion()
{
   // Create a new empty region.

   return (Region_t) gdk_region_new();
}

//______________________________________________________________________________
void TGWin32::DestroyRegion(Region_t reg)
{
   // Destroy region.

   gdk_region_destroy((GdkRegion *) reg);
}

//______________________________________________________________________________
void TGWin32::UnionRectWithRegion(Rectangle_t * rect, Region_t src, Region_t dest)
{
   // Union of rectangle with a region.

   GdkRectangle r;
   r.x = rect->fX;
   r.y = rect->fY;
   r.width = rect->fWidth;
   r.height = rect->fHeight;
   dest = (Region_t) gdk_region_union_with_rect((GdkRegion *) src, &r);
}

//______________________________________________________________________________
Region_t TGWin32::PolygonRegion(Point_t * points, Int_t np, Bool_t winding)
{
   // Create region for the polygon defined by the points array.
   // If winding is true use WindingRule else EvenOddRule as fill rule.

   return (Region_t) gdk_region_polygon((GdkPoint*)points, np,
                                 winding ? GDK_WINDING_RULE : GDK_EVEN_ODD_RULE);
}

//______________________________________________________________________________
void TGWin32::UnionRegion(Region_t rega, Region_t regb, Region_t result)
{
   // Compute the union of rega and regb and return result region.
   // The output region may be the same result region.

   result = (Region_t) gdk_regions_union((GdkRegion *) rega, (GdkRegion *) regb);
}

//______________________________________________________________________________
void TGWin32::IntersectRegion(Region_t rega, Region_t regb,
                              Region_t result)
{
   // Compute the intersection of rega and regb and return result region.
   // The output region may be the same as the result region.

   result = (Region_t) gdk_regions_intersect((GdkRegion *) rega,(GdkRegion *) regb);
}

//______________________________________________________________________________
void TGWin32::SubtractRegion(Region_t rega, Region_t regb, Region_t result)
{
   // Subtract rega from regb.

   result = (Region_t)gdk_regions_subtract((GdkRegion *) rega,(GdkRegion *) regb);
}

//______________________________________________________________________________
void TGWin32::XorRegion(Region_t rega, Region_t regb, Region_t result)
{
   // Calculate the difference between the union and intersection of
   // two regions.

   result = (Region_t) gdk_regions_xor((GdkRegion *) rega, (GdkRegion *) regb);
}

//______________________________________________________________________________
Bool_t TGWin32::EmptyRegion(Region_t reg)
{
   // Return true if the region is empty.

   return (Bool_t) gdk_region_empty((GdkRegion *) reg);
}

//______________________________________________________________________________
Bool_t TGWin32::PointInRegion(Int_t x, Int_t y, Region_t reg)
{
   // Returns true if the point x,y is in the region.

   return (Bool_t) gdk_region_point_in((GdkRegion *) reg, x, y);
}

//______________________________________________________________________________
Bool_t TGWin32::EqualRegion(Region_t rega, Region_t regb)
{
   // Returns true if two regions are equal.

   return (Bool_t) gdk_region_equal((GdkRegion *) rega, (GdkRegion *) regb);
}

//______________________________________________________________________________
void TGWin32::GetRegionBox(Region_t reg, Rectangle_t * rect)
{
   // Return smallest enclosing rectangle.

   GdkRectangle r;
   gdk_region_get_clipbox((GdkRegion *) reg, &r);
   rect->fX = r.x;
   rect->fY = r.y;
   rect->fWidth = r.width;
   rect->fHeight = r.height;
}

//______________________________________________________________________________
char **TGWin32::ListFonts(const char *fontname, Int_t /*max*/, Int_t &count)
{
   // Return list of font names matching "fontname".

   char  foundry[32], family[100], weight[32], slant[32], font_name[256];
   char  **fontlist;
   Int_t n1, fontcount = 0;

   sscanf(fontname, "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%n",
          foundry, family, weight, slant, &n1);
   // replace "medium" by "normal"
   if(!stricmp(weight,"medium")) {
      sprintf(weight,"normal");
   }
   // since all sizes are allowed with TTF, just forget it...
   sprintf(font_name, "-%s-%s-%s-%s-*", foundry, family, weight, slant);
   fontlist = gdk_font_list_new(font_name, &fontcount);
   count = fontcount;

   if (fontcount > 0) return fontlist;
   return 0;
}

//______________________________________________________________________________
void TGWin32::FreeFontNames(char **fontlist)
{
   //

   gdk_font_list_free(fontlist);
}

//______________________________________________________________________________
Drawable_t TGWin32::CreateImage(UInt_t width, UInt_t height)
{
   //

   return (Drawable_t) gdk_image_new(GDK_IMAGE_SHARED, gdk_visual_get_best(),
                                     width, height);
}

//______________________________________________________________________________
void TGWin32::GetImageSize(Drawable_t id, UInt_t &width, UInt_t &height)
{
   //

   width  = ((GdkImage*)id)->width;
   height = ((GdkImage*)id)->height;
}

//______________________________________________________________________________
void TGWin32::PutPixel(Drawable_t id, Int_t x, Int_t y, ULong_t pixel)
{
   //

   if (!id) return;

   GdkImage *image = (GdkImage *)id;
   if (image->depth == 1) {
      if (pixel & 1) {
         ((UChar_t *) image->mem)[y * image->bpl + (x >> 3)] |= (1 << (7 - (x & 0x7)));
      } else {
         ((UChar_t *) image->mem)[y * image->bpl + (x >> 3)] &= ~(1 << (7 - (x & 0x7)));
      }
   } else {
      UChar_t *pixelp = (UChar_t *) image->mem + y * image->bpl + x * image->bpp;
      // Windows is always LSB, no need to check image->byte_order.
      switch (image->bpp) {
         case 4:
            pixelp[3] = 0;
         case 3:
            pixelp[2] = ((pixel >> 16) & 0xFF);
         case 2:
            pixelp[1] = ((pixel >> 8) & 0xFF);
         case 1:
            pixelp[0] = (pixel & 0xFF);
      }
   }
}

//______________________________________________________________________________
void TGWin32::PutImage(Drawable_t id, GContext_t gc, Drawable_t img, Int_t dx,
                       Int_t dy, Int_t x, Int_t y, UInt_t w, UInt_t h)
{
   //

   if (!id) return;

   gdk_draw_image((GdkDrawable *) id, (GdkGC *)gc, (GdkImage *)img,
                  x, y, dx, dy, w, h);
   ::GdiFlush();
}

//______________________________________________________________________________
void TGWin32::DeleteImage(Drawable_t img)
{
   //

   gdk_image_unref((GdkImage *)img);
}

//______________________________________________________________________________
unsigned char *TGWin32::GetColorBits(Drawable_t wid,  Int_t x, Int_t y,
                                     UInt_t width, UInt_t height)
{
   // Gets DIB bits
   // x, y, width, height - position of bitmap
   // returns a pointer on bitmap bits array
   // in format:
   // b1, g1, r1, 0,  b2, g2, r2, 0 ... bn, gn, rn, 0 ..
   //
   // Pixels are numbered from left to right and from top to bottom.
   // By default all pixels from the whole drawable are returned.

   HDC hdc, memdc;
   BITMAPINFO bmi;
   HGDIOBJ oldbitmap1, oldbitmap2;
   BITMAP bm;
   HBITMAP ximage = 0;
   VOID  *bmbits = 0;
   unsigned char *ret = 0;

   if (GDK_DRAWABLE_TYPE(wid) == GDK_DRAWABLE_PIXMAP) {
      hdc = ::CreateCompatibleDC(NULL);
      oldbitmap1 = ::SelectObject(hdc, GDK_DRAWABLE_XID(wid));
      ::GetObject(GDK_DRAWABLE_XID(wid), sizeof(BITMAP), &bm);
   } else {
      hdc = ::GetDC((HWND)GDK_DRAWABLE_XID(wid));
   }
   memdc = ::CreateCompatibleDC(hdc);

   bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   bmi.bmiHeader.biWidth = width;
   bmi.bmiHeader.biHeight = -1 * (int)(height);
   bmi.bmiHeader.biPlanes = 1;
   bmi.bmiHeader.biBitCount = 32;
   bmi.bmiHeader.biCompression = BI_RGB;
   bmi.bmiHeader.biSizeImage = 0;
   bmi.bmiHeader.biXPelsPerMeter = bmi.bmiHeader.biYPelsPerMeter = 0;
   bmi.bmiHeader.biClrUsed = 0;
   bmi.bmiHeader.biClrImportant = 0;

   ximage = ::CreateDIBSection(hdc, (BITMAPINFO *) &bmi, DIB_RGB_COLORS, &bmbits, NULL, 0);

   if (ximage && bmbits) {
      oldbitmap2 = ::SelectObject(memdc, ximage);
      ::BitBlt(memdc, x, y, width, height, hdc, 0, 0, SRCCOPY);
      ::SelectObject(memdc, oldbitmap2);
   }
   ::DeleteDC(memdc);
   if (GDK_DRAWABLE_TYPE(wid) == GDK_DRAWABLE_PIXMAP) {
      ::SelectObject(hdc, oldbitmap1);
      ::DeleteDC(hdc);
   } else {
      ::ReleaseDC((HWND)GDK_DRAWABLE_XID(wid), hdc);
   }
   if (ximage && bmbits) {
      ULong_t sz = width*height*4;
      ret = new unsigned char[sz];
      memcpy(ret, bmbits, sz);
      ::DeleteObject(ximage);
   }
   return ret;
}

//______________________________________________________________________________
Pixmap_t TGWin32::CreatePixmapFromData(unsigned char *bits, UInt_t width, UInt_t height)
{
   // create an image from RGB data. RGB data is in format :
   // b1, g1, r1, 0,  b2, g2, r2, 0 ... bn, gn, rn, 0 ..
   //
   // Pixels are numbered from left to right and from top to bottom.
   // Note that data must be 32-bit aligned

   BITMAPINFO bmp_info;
   bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   bmp_info.bmiHeader.biWidth = width;
   bmp_info.bmiHeader.biHeight = -1 * (int)(height);
   bmp_info.bmiHeader.biPlanes = 1;
   bmp_info.bmiHeader.biBitCount = 32;
   bmp_info.bmiHeader.biCompression = BI_RGB;
   bmp_info.bmiHeader.biSizeImage = 0;
   bmp_info.bmiHeader.biClrUsed = 0;
   bmp_info.bmiHeader.biXPelsPerMeter = 0L;
   bmp_info.bmiHeader.biYPelsPerMeter = 0L;
   bmp_info.bmiHeader.biClrImportant = 0;
   bmp_info.bmiColors[0].rgbRed = 0;
   bmp_info.bmiColors[0].rgbGreen = 0;
   bmp_info.bmiColors[0].rgbBlue = 0;
   bmp_info.bmiColors[0].rgbReserved = 0;

   HDC hdc = ::GetDC(NULL);
   HBITMAP hbitmap = ::CreateDIBitmap(hdc, &bmp_info.bmiHeader, CBM_INIT,
                                      (void *)bits, &bmp_info, DIB_RGB_COLORS);
   ::ReleaseDC(NULL, hdc);

   SIZE size;
   // For an obscure reason, we have to set the size of the
   // bitmap this way before to call gdk_pixmap_foreign_new
   // otherwise, it fails...
   ::SetBitmapDimensionEx(hbitmap,width, height, &size);

   return (Pixmap_t)gdk_pixmap_foreign_new((guint32)hbitmap);
}

//______________________________________________________________________________
Int_t TGWin32::AddPixmap(ULong_t pix, UInt_t w, UInt_t h)
{
   //register pixmap created by TGWin32GLManager
   HBITMAP hBmp = reinterpret_cast<HBITMAP>(pix);
   SIZE sz = SIZE();

   SetBitmapDimensionEx(hBmp, w, h, &sz);
   GdkPixmap *newPix = gdk_pixmap_foreign_new(reinterpret_cast<guint32>(hBmp));

   Int_t wid = 0;
   for(; wid < fMaxNumberOfWindows; ++wid)
      if (!fWindows[wid].open)
         break;

   if (wid == fMaxNumberOfWindows) {
      Int_t newSize = fMaxNumberOfWindows + 10;

      fWindows = (XWindow_t *)TStorage::ReAlloc(fWindows, newSize * sizeof(XWindow_t),
                                                fMaxNumberOfWindows * sizeof(XWindow_t));

      for (Int_t i = fMaxNumberOfWindows; i < newSize; ++i)
         fWindows[i].open = 0;

      fMaxNumberOfWindows = newSize;
   }

   fWindows[wid].open = 1;
   gCws = fWindows + wid;
   gCws->window = newPix;
   gCws->drawing = gCws->window;
   gCws->buffer = 0;
   gCws->double_buffer = 0;
   gCws->ispixmap = 1;
   gCws->clip = 0;
   gCws->width = w;
   gCws->height = h;
   gCws->new_colors = 0;

   return wid;
}

//______________________________________________________________________________
Int_t TGWin32::AddWindow(ULong_t qwid, UInt_t w, UInt_t h)
{
   // Register a window created by Qt as a ROOT window (like InitWindow()).

   Int_t wid;
   // Select next free window number

 again:
   for (wid = 0; wid < fMaxNumberOfWindows; wid++) {
      if (!fWindows[wid].open) {
         fWindows[wid].open = 1;
         fWindows[wid].double_buffer = 0;
         gCws = &fWindows[wid];
         break;
      }
   }

   if (wid == fMaxNumberOfWindows) {
      int newsize = fMaxNumberOfWindows + 10;
      fWindows =
          (XWindow_t *) TStorage::ReAlloc(fWindows,
                                          newsize * sizeof(XWindow_t),
                                          fMaxNumberOfWindows *
                                          sizeof(XWindow_t));

      for (int i = fMaxNumberOfWindows; i < newsize; i++) {
         fWindows[i].open = 0;
      }

      fMaxNumberOfWindows = newsize;
      goto again;
   }

   gCws->window = gdk_window_foreign_new((guint32)qwid);

   gCws->drawing       = gCws->window;
   gCws->buffer        = 0;
   gCws->double_buffer = 0;
   gCws->ispixmap      = 0;
   gCws->clip          = 0;
   gCws->width         = w;
   gCws->height        = h;
   gCws->new_colors    = 0;

   return wid;
}

//______________________________________________________________________________
void TGWin32::RemoveWindow(ULong_t qwid)
{
   // Remove a window created by Qt (like CloseWindow1()).

   int wid;

   SelectWindow((int)qwid);

   if (gCws->buffer) {
      gdk_pixmap_unref(gCws->buffer);
   }
   if (gCws->new_colors) {
      gdk_colormap_free_colors((GdkColormap *) fColormap,
                               (GdkColor *)gCws->new_colors, gCws->ncolors);

      delete [] gCws->new_colors;
      gCws->new_colors = 0;
   }

   GdiFlush();
   gCws->open = 0;

   if (!fWindows) return;

   // make first window in list the current window
   for (wid = 0; wid < fMaxNumberOfWindows; wid++) {
      if (fWindows[wid].open) {
         gCws = &fWindows[wid];
         return;
      }
   }
   gCws = 0;
}

//______________________________________________________________________________
void TGWin32::ShapeCombineMask(Window_t id, Int_t x, Int_t y, Pixmap_t mask)
{
   // The Nonrectangular Window Shape Extension adds nonrectangular
   // windows to the System.
   // This allows for making shaped (partially transparent) windows

   gdk_window_shape_combine_mask((GdkWindow *)id, (GdkBitmap *) mask, x, y);
}

//______________________________________________________________________________
UInt_t TGWin32::ScreenWidthMM() const
{
   // Returns the width of the screen in millimeters.

   return (UInt_t)gdk_screen_width_mm();
}

//------------------------------ Drag and Drop ---------------------------------

//______________________________________________________________________________
void TGWin32::DeleteProperty(Window_t win, Atom_t& prop)
{
   // Deletes the specified property on the specified window.

   HWND hWnd = (HWND)GDK_DRAWABLE_XID((GdkWindow *)win);
   Atom_t atom = (Atom_t)GetProp(hWnd,(LPCTSTR)MAKELONG(prop,0));
   if (atom != 0) {
	   GlobalDeleteAtom(atom);
   }
   RemoveProp(hWnd,(LPCTSTR)MAKELONG(prop,0));
}

//______________________________________________________________________________
Int_t TGWin32::GetProperty(Window_t win, Atom_t prop, Long_t offset, Long_t len,
                         Bool_t del, Atom_t req_type, Atom_t *act_type,
                         Int_t *act_format, ULong_t *nitems, ULong_t *bytes,
                         unsigned char **prop_list)
{
   // Returns the actual type of the property, the actual format of the property,
   // and a pointer to the data actually returned.
   
   HGLOBAL hdata;
   UChar_t *ptr, *data;
   UInt_t i, n, length;

   HWND hWnd = (HWND)GDK_DRAWABLE_XID((GdkWindow *)win);
   if (hWnd == NULL)
      return 0;

   Atom_t dndproxy = InternAtom("XdndProxy", kFALSE);
   Atom_t dndtypelist = InternAtom("XdndTypeList", kFALSE);

   if (prop == dndproxy)
      return 0;
   if (prop == dndtypelist) {
      *act_type = XA_ATOM;
      *prop_list = (unsigned char *)GetProp(hWnd, (LPCTSTR)MAKELONG(prop,0));
      for (n = 0; prop_list[n]; n++);
      *nitems = n;
      return n;
   }
   else {
      if (!OpenClipboard((HWND)GDK_DRAWABLE_XID((GdkWindow *)win))) {
         return 0;
      }
      hdata = GetClipboardData(CF_PRIVATEFIRST);
      ptr = (UChar_t *)GlobalLock(hdata);
      length = GlobalSize(hdata);
      data = (UChar_t *)malloc(length + 1);
      for (i = 0; i < length; i++) {
         data[i] = ptr[i];
      }
      GlobalUnlock(hdata);
      CloseClipboard();
      *prop_list = data;
      *bytes = *nitems = length;
      return length;
   }
   return 0;
}

//______________________________________________________________________________
void TGWin32::ChangeActivePointerGrab(Window_t win, UInt_t mask, Cursor_t cur)
{
   // Changes the active cursor of the specified window.

   UInt_t xevmask;
   MapEventMask(mask, xevmask);
   if (cur == kNone)
      gdk_window_set_cursor((GdkWindow *) win, fCursors[kHand]);
   else
      gdk_window_set_cursor((GdkWindow *) win, (GdkCursor *)cur);
}

//______________________________________________________________________________
void TGWin32::ConvertSelection(Window_t win, Atom_t &sel, Atom_t &target,
                             Atom_t &prop, Time_t &stamp)
{
   // Get Clipboard data.

   HGLOBAL hdata;

   static UINT gdk_selection_notify_msg = 
      RegisterWindowMessage("gdk-selection-notify");
   HWND hWnd = (HWND)GDK_DRAWABLE_XID((GdkWindow *)win);
   if (!OpenClipboard((HWND)GDK_DRAWABLE_XID((GdkWindow *)win))) {
      return;
   }
   hdata = GetClipboardData(CF_PRIVATEFIRST);
   CloseClipboard();
   if (hdata == 0)
      return;
   /* Send ourselves an ersatz selection notify message so that we actually
    * fetch the data.
    */
   PostMessage(hWnd, gdk_selection_notify_msg, sel, target);
}

//______________________________________________________________________________
Bool_t TGWin32::SetSelectionOwner(Window_t owner, Atom_t &sel)
{
   // Assigns owner of Clipboard.

   static UINT gdk_selection_request_msg = 
      RegisterWindowMessage("gdk-selection-request");
   HWND hWnd = (HWND)GDK_DRAWABLE_XID((GdkWindow *)owner);
   OpenClipboard(hWnd);
   EmptyClipboard();
   CloseClipboard();
   if (owner) {
      ::PostMessage(hWnd, gdk_selection_request_msg, sel, 0);
   }
   return kTRUE;
}

//______________________________________________________________________________
void TGWin32::ChangeProperties(Window_t id, Atom_t property, Atom_t type,
                               Int_t format, UChar_t *data, Int_t len)
{
   // Put data into Clipboard.

   HGLOBAL hdata;
   Int_t i;
   UChar_t *ptr;

   if (data == 0 || len == 0)
      return;
   if (!OpenClipboard((HWND)GDK_DRAWABLE_XID((GdkWindow *)id))) {
      return;
   }
   hdata = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len + 1);
   ptr = (UChar_t *)GlobalLock(hdata);
   for (i = 0; i < len; i++) {
      *ptr++ = *data++;
   }
   GlobalUnlock(hdata);
   SetClipboardData(CF_PRIVATEFIRST, hdata);
   CloseClipboard();
}

//______________________________________________________________________________
void TGWin32::SetTypeList(Window_t win, Atom_t prop, Atom_t *typelist)
{
   // Add the list of drag and drop types to the Window win.

   SetProp((HWND)GDK_DRAWABLE_XID((GdkWindow *)win),
           (LPCTSTR)MAKELONG(prop,0),
           (HANDLE)typelist);
}

//______________________________________________________________________________
Window_t TGWin32::FindRWindow(Window_t root, Window_t dragwin, Window_t input, 
                              int x, int y, int maxd)
{
   // Recursively search in the children of Window for a Window which is at 
   // location x, y and is DND aware, with a maximum depth of maxd.
   // Possibility to exclude dragwin and input.

   POINT cpt, point;
   RECT  rect;
   HWND hwnd, hwndc, hwndt;
   Window_t win, retwin = kNone;
   Atom_t version = 0;
   Atom_t dndaware = InternAtom("XdndAware", kFALSE);

   cpt.x = x;
   cpt.y = y;
   hwnd = ::ChildWindowFromPointEx((HWND)GDK_DRAWABLE_XID((GdkWindow *)root),
                                    cpt, CWP_ALL);
   while (hwnd) {
      GetWindowRect(hwnd, &rect);
      if (PtInRect(&rect, cpt)) {
         if (GetProp(hwnd,(LPCTSTR)MAKELONG(dndaware,0))) {
            win = (Window_t) gdk_xid_table_lookup(hwnd);
            if (win && win != dragwin && win != input)
               return win;
         }
         Bool_t done = kFALSE;
         hwndt = hwnd;
         while (!done) {
            point = cpt;
            ::MapWindowPoints(NULL, hwndt, &point, 1);
            hwndc = ChildWindowFromPoint (hwndt, point);
            if (GetProp(hwnd,(LPCTSTR)MAKELONG(dndaware,0))) {
               win = (Window_t) gdk_xid_table_lookup(hwndc);
               if (win && win != dragwin && win != input)
                  return win;
            }
            if (hwndc == NULL)
               done = TRUE;
            else if (hwndc == hwndt)
               done = TRUE;
            else
               hwndt = hwndc;
            if (GetProp(hwndt,(LPCTSTR)MAKELONG(dndaware,0))) {
               win = (Window_t) gdk_xid_table_lookup(hwndt);
               if (win && win != dragwin && win != input)
                  return win;
            }
         }
      }
      hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
   }
   return kNone;
}

//______________________________________________________________________________
Bool_t TGWin32::IsDNDAware(Window_t win, Atom_t *typelist)
{
   // Checks if Window win is DND aware, and knows any of the DND formats
   // passed in argument.

   if (!win) return kFALSE;

   Atom_t version = 0;
   Atom_t dndaware = InternAtom("XdndAware", kFALSE);
   HWND window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)win);
   while (window) {
      version = (Atom_t)GetProp(window,(LPCTSTR)MAKELONG(dndaware,0));
      if (version) return kTRUE;
      window = ::GetParent(window);
   }
   return kFALSE;
}

//______________________________________________________________________________
void TGWin32::SetDNDAware(Window_t id, Atom_t *typelist)
{
   // Add XdndAware property and the list of drag and drop types to the 
   // Window win.

   int n;
   if (!id) return;

   DWORD dwStyle = GetWindowLong((HWND)GDK_DRAWABLE_XID((GdkWindow *)id), 
                                 GWL_EXSTYLE);
   SetWindowLong((HWND)GDK_DRAWABLE_XID((GdkWindow *)id), GWL_EXSTYLE, 
                 dwStyle | WS_EX_ACCEPTFILES);
   Atom_t dndaware = InternAtom("XdndAware", kFALSE);
   SetProp((HWND)GDK_DRAWABLE_XID((GdkWindow *)id),
           (LPCTSTR)MAKELONG(dndaware,0),
           (HANDLE)XDND_PROTOCOL_VERSION);

   if (typelist == 0)
      return;
   for (n = 0; typelist[n]; n++);
   Atom_t dndtypelist = InternAtom("XdndTypeList", kFALSE);
   SetProp((HWND)GDK_DRAWABLE_XID((GdkWindow *)id),
           (LPCTSTR)MAKELONG(dndtypelist,0),
           (HANDLE)typelist);

}

//______________________________________________________________________________
void TGWin32::SetUserThreadId(ULong_t id)
{
   // Set user thread id. This is used when an extra thread is created
   // to process events.

   if (id == 0) {
      TGWin32ProxyBase::fgMainThreadId = ((TWinNTSystem*)gSystem)->GetGUIThreadId();
   }
   else {
      TGWin32ProxyBase::fgUserThreadId = id;
   }
}

