Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGWin32.cxx
Go to the documentation of this file.
1 // @(#)root/win32gdk:$Id$
2 // Author: Rene Brun, Olivier Couet, Fons Rademakers, Valeri Onuchin, Bertrand Bellenot 27/11/01
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /// \defgroup win32 Win32 backend
13 /// \brief Interface to Windows graphics.
14 /// \ingroup GraphicsBackends
15 
16 /** \class TGWin32
17 \ingroup win32
18 This class is the basic interface to the Win32 graphics system.
19 It is an implementation of the abstract TVirtualX class.
20 
21 This code was initially developed in the context of HIGZ and PAW
22 by Olivier Couet (package X11INT).
23 */
24 
25 #include <ft2build.h>
26 #include FT_FREETYPE_H
27 #include FT_GLYPH_H
28 #include "TGWin32.h"
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include <limits.h>
34 #include <process.h>
35 #include <wchar.h>
36 #include "gdk/gdkkeysyms.h"
37 #include "xatom.h"
38 #include <winuser.h>
39 
40 #include "TROOT.h"
41 #include "TApplication.h"
42 #include "TColor.h"
43 #include "TPoint.h"
44 #include "TMath.h"
45 #include "TStorage.h"
46 #include "TStyle.h"
47 #include "TSystem.h"
48 #include "TGFrame.h"
49 #include "TError.h"
50 #include "TException.h"
51 #include "TClassTable.h"
52 #include "KeySymbols.h"
53 #include "TWinNTSystem.h"
54 #include "TGWin32VirtualXProxy.h"
55 #include "TWin32SplashThread.h"
56 #include "TString.h"
57 #include "TObjString.h"
58 #include "TObjArray.h"
59 #include "TExMap.h"
60 #include "TEnv.h"
61 #include "RStipples.h"
62 #include "TEnv.h"
63 
64 // DND protocol version
65 #define XDND_PROTOCOL_VERSION 5
66 #ifndef IDC_HAND
67 #define IDC_HAND MAKEINTRESOURCE(32649)
68 #endif
69 
70 extern "C" {
71 void gdk_win32_draw_rectangle (GdkDrawable *drawable,
72  GdkGC *gc,
73  gint filled,
74  gint x,
75  gint y,
76  gint width,
77  gint height);
78 void gdk_win32_draw_arc (GdkDrawable *drawable,
79  GdkGC *gc,
80  gint filled,
81  gint x,
82  gint y,
83  gint width,
84  gint height,
85  gint angle1,
86  gint angle2);
87 void gdk_win32_draw_polygon (GdkDrawable *drawable,
88  GdkGC *gc,
89  gint filled,
90  GdkPoint *points,
91  gint npoints);
92 void gdk_win32_draw_text (GdkDrawable *drawable,
93  GdkFont *font,
94  GdkGC *gc,
95  gint x,
96  gint y,
97  const gchar *text,
98  gint text_length);
99 void gdk_win32_draw_points (GdkDrawable *drawable,
100  GdkGC *gc,
101  GdkPoint *points,
102  gint npoints);
103 void gdk_win32_draw_segments (GdkDrawable *drawable,
104  GdkGC *gc,
105  GdkSegment *segs,
106  gint nsegs);
107 void gdk_win32_draw_lines (GdkDrawable *drawable,
108  GdkGC *gc,
109  GdkPoint *points,
110  gint npoints);
111 
112 };
113 
114 //////////// internal classes & structures (very private) ////////////////
115 
116 struct XWindow_t {
117  Int_t open; // 1 if the window is open, 0 if not
118  Int_t double_buffer; // 1 if the double buffer is on, 0 if not
119  Int_t ispixmap; // 1 if pixmap, 0 if not
120  GdkDrawable *drawing; // drawing area, equal to window or buffer
121  GdkDrawable *window; // win32 window
122  GdkDrawable *buffer; // pixmap used for double buffer
123  UInt_t width; // width of the window
124  UInt_t height; // height of the window
125  Int_t clip; // 1 if the clipping is on
126  Int_t xclip; // x coordinate of the clipping rectangle
127  Int_t yclip; // y coordinate of the clipping rectangle
128  UInt_t wclip; // width of the clipping rectangle
129  UInt_t hclip; // height of the clipping rectangle
130  ULong_t *new_colors; // new image colors (after processing)
131  Int_t ncolors; // number of different colors
132 };
133 
134 
135 /////////////////////////////////// globals //////////////////////////////////
136 int gdk_debug_level;
137 
138 namespace {
139 /////////////////////////////////// globals //////////////////////////////////
140 
141 GdkAtom gClipboardAtom = GDK_NONE;
142 static XWindow_t *gCws; // gCws: pointer to the current window
143 static XWindow_t *gTws; // gTws: temporary pointer
144 
145 //
146 // gColors[0] : background also used for b/w screen
147 // gColors[1] : foreground also used for b/w screen
148 // gColors[2..kMAXCOL-1]: colors which can be set by SetColor
149 //
150 const Int_t kBIGGEST_RGB_VALUE = 65535;
151 //const Int_t kMAXCOL = 1000;
152 //static struct {
153 // Int_t defined;
154 // GdkColor color;
155 //} gColors[kMAXCOL];
156 
157 //
158 // Primitives Graphic Contexts global for all windows
159 //
160 const int kMAXGC = 7;
161 static GdkGC *gGClist[kMAXGC];
162 static GdkGC *gGCline; // = gGClist[0]; // PolyLines
163 static GdkGC *gGCmark; // = gGClist[1]; // PolyMarker
164 static GdkGC *gGCfill; // = gGClist[2]; // Fill areas
165 static GdkGC *gGCtext; // = gGClist[3]; // Text
166 static GdkGC *gGCinvt; // = gGClist[4]; // Inverse text
167 static GdkGC *gGCdash; // = gGClist[5]; // Dashed lines
168 static GdkGC *gGCpxmp; // = gGClist[6]; // Pixmap management
169 
170 static GdkGC *gGCecho; // Input echo
171 
172 static Int_t gFillHollow; // Flag if fill style is hollow
173 static GdkPixmap *gFillPattern; // Fill pattern
174 
175 //
176 // Text management
177 //
178 static const char *gTextFont = "arial.ttf"; // Current font
179 
180 //
181 // Markers
182 //
183 const Int_t kMAXMK = 100;
184 static struct {
185  int type;
186  int n;
187  GdkPoint xy[kMAXMK];
188 } gMarker; // Point list to draw marker
189 
190 //
191 // Keep style values for line GdkGC
192 //
193 static int gLineWidth = 0;
194 static int gLineStyle = GDK_LINE_SOLID;
195 static int gCapStyle = GDK_CAP_BUTT;
196 static int gJoinStyle = GDK_JOIN_MITER;
197 static char gDashList[10];
198 static int gDashLength = 0;
199 static int gDashOffset = 0;
200 static int gDashSize = 0;
201 
202 //
203 // Event masks
204 //
205 static ULong_t gMouseMask =
206  GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK
207  | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK
208  | GDK_KEY_RELEASE_MASK;
209 static ULong_t gKeybdMask =
210  GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK | GDK_ENTER_NOTIFY_MASK |
211  GDK_LEAVE_NOTIFY_MASK;
212 
213 //
214 // Data to create an invisible cursor
215 //
216 const char null_cursor_bits[] = {
217  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
220 };
221 static GdkCursor *gNullCursor;
222 
223 static bool gdk_initialized = false;
224 
225 //---- MWM Hints stuff
226 
227 struct MWMHintsProperty_t {
228  Handle_t fFlags;
229  Handle_t fFunctions;
230  Handle_t fDecorations;
231  Int_t fInputMode;
232 };
233 
234 //---- hints
235 
236 const ULong_t kMWMHintsFunctions = BIT(0);
237 const ULong_t kMWMHintsDecorations = BIT(1);
238 const ULong_t kMWMHintsInputMode = BIT(2);
239 
240 const Int_t kPropMotifWMHintsElements = 4;
241 const Int_t kPropMWMHintElements = kPropMotifWMHintsElements;
242 
243 
244 //---- Key symbol mapping
245 
246 struct KeySymbolMap_t {
247  KeySym fXKeySym;
248  EKeySym fKeySym;
249 };
250 
251 static const char *keyCodeToString[] = {
252  "", /* 0x000 */
253  "", /* 0x001, VK_LBUTTON */
254  "", /* 0x002, VK_RBUTTON */
255  "", /* 0x003, VK_CANCEL */
256  "", /* 0x004, VK_MBUTTON */
257  "", /* 0x005 */
258  "", /* 0x006 */
259  "", /* 0x007 */
260  "\015", /* 0x008, VK_BACK */
261  "\t", /* 0x009, VK_TAB */
262  "", /* 0x00A */
263  "", /* 0x00B */
264  "", /* 0x00C, VK_CLEAR */
265  "\r", /* 0x00D, VK_RETURN */
266  "", /* 0x00E */
267  "", /* 0x00F */
268  "", /* 0x010, VK_SHIFT */
269  "", /* 0x011, VK_CONTROL */
270  "", /* 0x012, VK_MENU */
271  "", /* 0x013, VK_PAUSE */
272  "", /* 0x014, VK_CAPITAL */
273  "", /* 0x015, VK_KANA */
274  "", /* 0x016 */
275  "", /* 0x017 */
276  "", /* 0x018 */
277  "", /* 0x019, VK_KANJI */
278  "", /* 0x01A */
279  "", /* 0x01B, VK_ESCAPE */
280  "", /* 0x01C, VK_CONVERT */
281  "", /* 0x01D, VK_NONCONVERT */
282  "", /* 0x01E */
283  "", /* 0x01F */
284  " ", /* 0x020, VK_SPACE */
285  "", /* 0x021, VK_PRIOR */
286  "", /* 0x022, VK_NEXT */
287  "", /* 0x023, VK_END */
288  "", /* 0x024, VK_HOME */
289  "", /* 0x025, VK_LEFT */
290  "", /* 0x026, VK_UP */
291  "", /* 0x027, VK_RIGHT */
292  "", /* 0x028, VK_DOWN */
293  "", /* 0x029, VK_SELECT */
294  "", /* 0x02A, VK_PRINT */
295  "", /* 0x02B, VK_EXECUTE */
296  "", /* 0x02C, VK_SNAPSHOT */
297  "", /* 0x02D, VK_INSERT */
298  "\037", /* 0x02E, VK_DELETE */
299  "", /* 0x02F, VK_HELP */
300 };
301 
302 //---- Mapping table of all non-trivial mappings (the ASCII keys map
303 //---- one to one so are not included)
304 
305 static KeySymbolMap_t gKeyMap[] = {
306  {GDK_Escape, kKey_Escape},
307  {GDK_Tab, kKey_Tab},
308 #ifndef GDK_ISO_Left_Tab
309  {0xFE20, kKey_Backtab},
310 #else
311  {GDK_ISO_Left_Tab, kKey_Backtab},
312 #endif
313  {GDK_BackSpace, kKey_Backspace},
314  {GDK_Return, kKey_Return},
315  {GDK_Insert, kKey_Insert},
316  {GDK_Delete, kKey_Delete},
317  {GDK_Clear, kKey_Delete},
318  {GDK_Pause, kKey_Pause},
319  {GDK_Print, kKey_Print},
320  {0x1005FF60, kKey_SysReq}, // hardcoded Sun SysReq
321  {0x1007ff00, kKey_SysReq}, // hardcoded X386 SysReq
322  {GDK_Home, kKey_Home}, // cursor movement
323  {GDK_End, kKey_End},
324  {GDK_Left, kKey_Left},
325  {GDK_Up, kKey_Up},
326  {GDK_Right, kKey_Right},
327  {GDK_Down, kKey_Down},
328  {GDK_Prior, kKey_Prior},
329  {GDK_Next, kKey_Next},
330  {GDK_Shift_L, kKey_Shift}, // modifiers
331  {GDK_Shift_R, kKey_Shift},
332  {GDK_Shift_Lock, kKey_Shift},
333  {GDK_Control_L, kKey_Control},
334  {GDK_Control_R, kKey_Control},
335  {GDK_Meta_L, kKey_Meta},
336  {GDK_Meta_R, kKey_Meta},
337  {GDK_Alt_L, kKey_Alt},
338  {GDK_Alt_R, kKey_Alt},
339  {GDK_Caps_Lock, kKey_CapsLock},
340  {GDK_Num_Lock, kKey_NumLock},
341  {GDK_Scroll_Lock, kKey_ScrollLock},
342  {GDK_KP_Space, kKey_Space}, // numeric keypad
343  {GDK_KP_Tab, kKey_Tab},
344  {GDK_KP_Enter, kKey_Enter},
345  {GDK_KP_Equal, kKey_Equal},
346  {GDK_KP_Multiply, kKey_Asterisk},
347  {GDK_KP_Add, kKey_Plus},
348  {GDK_KP_Separator, kKey_Comma},
349  {GDK_KP_Subtract, kKey_Minus},
350  {GDK_KP_Decimal, kKey_Period},
351  {GDK_KP_Divide, kKey_Slash},
352  {0, (EKeySym) 0}
353 };
354 
355 
356 /////////////////////static auxilary functions /////////////////////////////////
357 ////////////////////////////////////////////////////////////////////////////////
358 
359 static Int_t _lookup_string(Event_t * event, char *buf, Int_t buflen)
360 {
361  int i;
362  int n = event->fUser[1];
363  if (n > 0) {
364  for (i = 0; i < n; i++) {
365  buf[i] = event->fUser[2 + i];
366  }
367  buf[n] = 0;
368  } else {
369  buf[0] = 0;
370  }
371  if (event->fCode <= 0x20) {
372  strncpy(buf, keyCodeToString[event->fCode], buflen - 1);
373  }
374  return n;
375 }
376 
377 ////////////////////////////////////////////////////////////////////////////////
378 
379 inline void SplitLong(Long_t ll, Long_t & i1, Long_t & i2)
380 {
381  union {
382  Long_t l;
383  Int_t i[2];
384  } conv;
385 
386  conv.l = 0L;
387  conv.i[0] = 0;
388  conv.i[1] = 0;
389 
390  conv.l = ll;
391  i1 = conv.i[0];
392  i2 = conv.i[1];
393 }
394 
395 ////////////////////////////////////////////////////////////////////////////////
396 
397 inline void AsmLong(Long_t i1, Long_t i2, Long_t & ll)
398 {
399  union {
400  Long_t l;
401  Int_t i[2];
402  } conv;
403 
404  conv.i[0] = (Int_t) i1;
405  conv.i[1] = (Int_t) i2;
406  ll = conv.l;
407 }
408 
409 ////////////////////////////////////////////////////////////////////////////////
410 /// Make sure the child window is visible.
411 
412 static BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam)
413 {
414  ::ShowWindow(hwndChild, SW_SHOWNORMAL);
415  GdkWindow *child = gdk_window_lookup(hwndChild);
416  if (child)
417  ((GdkWindowPrivate *) child)->mapped = TRUE;
418  return TRUE;
419 }
420 
421 ////////////////////////////////////////////////////////////////////////////////
422 
423 static void _ChangeProperty(HWND w, char *np, char *dp, int n, Atom_t type)
424 {
425  HGLOBAL hMem;
426  char *p;
427 
428  hMem = ::GetProp(w, np);
429  if (hMem != NULL) {
430  ::GlobalFree(hMem);
431  }
432  hMem = ::GlobalAlloc(GHND, n + sizeof(Atom_t));
433  p = (char *) ::GlobalLock(hMem);
434  memcpy(p, &type, sizeof(Atom_t));
435  memcpy(p + sizeof(Atom_t), dp, n);
436  ::GlobalUnlock(hMem);
437  ::SetProp(w, np, hMem);
438  ::GlobalFree(hMem);
439 }
440 
441 ////////////////////////////////////////////////////////////////////////////////
442 ///
443 
444 static void W32ChangeProperty(HWND w, Atom_t property, Atom_t type,
445  int format, int mode, const unsigned char *data,
446  int nelements)
447 {
448  char *atomName;
449  char buffer[256];
450  int len;
451  char propName[32];
452 
453  if (mode == GDK_PROP_MODE_REPLACE || mode == GDK_PROP_MODE_PREPEND) {
454  len = (int) ::GlobalGetAtomName(property, buffer, sizeof(buffer));
455  if ((atomName = (char *) malloc(len + 1)) == NULL) {
456  return;
457  } else {
458  strcpy(atomName, buffer);
459  }
460  sprintf(propName, "#0x%0.4x", (unsigned) atomName);
461  _ChangeProperty(w, propName, (char *) data, nelements, type);
462  free(atomName);
463  }
464 }
465 
466 ////////////////////////////////////////////////////////////////////////////////
467 ///
468 
469 static int _GetWindowProperty(GdkWindow * id, Atom_t property, Long_t long_offset,
470  Long_t long_length, Bool_t delete_it, Atom_t req_type,
471  Atom_t * actual_type_return,
472  Int_t * actual_format_return, ULong_t * nitems_return,
473  ULong_t * bytes_after_return, UChar_t ** prop_return)
474 {
475  if (!id) return 0;
476 
477  char *data, *destPtr;
478  char propName[32];
479  HGLOBAL handle;
480  HWND w;
481 
482  w = (HWND) GDK_DRAWABLE_XID(id);
483 
484  if (::IsClipboardFormatAvailable(CF_TEXT) && ::OpenClipboard(NULL)) {
485  handle = ::GetClipboardData(CF_TEXT);
486  if (handle != NULL) {
487  data = (char *) ::GlobalLock(handle);
488  *nitems_return = strlen(data);
489  *prop_return = (UChar_t *) malloc(*nitems_return + 1);
490  destPtr = (char *) *prop_return;
491  while (*data != '\0') {
492  if (*data != '\r') {
493  *destPtr = *data;
494  destPtr++;
495  }
496  data++;
497  }
498  *destPtr = '\0';
499  ::GlobalUnlock(handle);
500  *actual_type_return = XA_STRING;
501  *bytes_after_return = 0;
502  }
503  ::CloseClipboard();
504  return 1;
505  }
506  if (delete_it) {
507  ::RemoveProp(w, propName);
508  }
509  return 1;
510 }
511 
512 ////////////////////////////////////////////////////////////////////////////////
513 ///
514 
515 static ULong_t GetPixelImage(Drawable_t id, Int_t x, Int_t y)
516 {
517  if (!id) return 0;
518 
519  GdkImage *image = (GdkImage *)id;
520  ULong_t pixel;
521 
522  if (image->depth == 1) {
523  pixel = (((char *) image->mem)[y * image->bpl + (x >> 3)] & (1 << (7 - (x & 0x7)))) != 0;
524  } else {
525  UChar_t *pixelp = (UChar_t *) image->mem + y * image->bpl + x * image->bpp;
526  switch (image->bpp) {
527  case 1:
528  pixel = *pixelp;
529  break;
530  // Windows is always LSB, no need to check image->byte_order.
531  case 2:
532  pixel = pixelp[0] | (pixelp[1] << 8);
533  break;
534  case 3:
535  pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
536  break;
537  case 4:
538  pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
539  break;
540  }
541  }
542  return pixel;
543 }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 /// Collect in orgcolors all different original image colors.
547 
548 static void CollectImageColors(ULong_t pixel, ULong_t * &orgcolors,
549  Int_t & ncolors, Int_t & maxcolors)
550 {
551  if (maxcolors == 0) {
552  ncolors = 0;
553  maxcolors = 100;
554  orgcolors = (ULong_t*) ::operator new(maxcolors*sizeof(ULong_t));
555  }
556 
557  for (int i = 0; i < ncolors; i++) {
558  if (pixel == orgcolors[i]) return;
559  }
560  if (ncolors >= maxcolors) {
561  orgcolors = (ULong_t *) TStorage::ReAlloc(orgcolors,
562  maxcolors * 2 *
563  sizeof(ULong_t),
564  maxcolors *
565  sizeof(ULong_t));
566  maxcolors *= 2;
567  }
568  orgcolors[ncolors++] = pixel;
569 }
570 
571 ////////////////////////////////////////////////////////////////////////////////
572 /// debug function for printing event mask
573 
574 static char *EventMask2String(UInt_t evmask)
575 {
576  static char bfr[500];
577  char *p = bfr;
578 
579  *p = '\0';
580 #define BITmask(x) \
581  if (evmask & k##x##Mask) \
582  p += sprintf (p, "%s" #x, (p > bfr ? " " : ""))
583  BITmask(Exposure);
584  BITmask(PointerMotion);
585  BITmask(ButtonMotion);
586  BITmask(ButtonPress);
587  BITmask(ButtonRelease);
588  BITmask(KeyPress);
589  BITmask(KeyRelease);
590  BITmask(EnterWindow);
591  BITmask(LeaveWindow);
592  BITmask(FocusChange);
593  BITmask(StructureNotify);
594 #undef BITmask
595 
596  return bfr;
597 }
598 
599 ///////////////////////////////////////////////////////////////////////////////
600 class TGWin32MainThread {
601 
602 public:
603  void *fHandle; // handle of server (aka command) thread
604  DWORD fId; // id of server (aka command) thread
605  static LPCRITICAL_SECTION fCritSec; // general mutex
606  static LPCRITICAL_SECTION fMessageMutex; // message queue mutex
607 
608  TGWin32MainThread();
609  ~TGWin32MainThread();
610  static void LockMSG();
611  static void UnlockMSG();
612 };
613 
614 TGWin32MainThread *gMainThread = 0;
615 LPCRITICAL_SECTION TGWin32MainThread::fCritSec = 0;
616 LPCRITICAL_SECTION TGWin32MainThread::fMessageMutex = 0;
617 
618 
619 ////////////////////////////////////////////////////////////////////////////////
620 /// dtor
621 
622 TGWin32MainThread::~TGWin32MainThread()
623 {
624  if (fCritSec) {
625  ::LeaveCriticalSection(fCritSec);
626  ::DeleteCriticalSection(fCritSec);
627  delete fCritSec;
628  }
629  fCritSec = 0;
630 
631  if (fMessageMutex) {
632  ::LeaveCriticalSection(fMessageMutex);
633  ::DeleteCriticalSection(fMessageMutex);
634  delete fMessageMutex;
635  }
636  fMessageMutex = 0;
637 
638  if(fHandle) {
639  ::PostThreadMessage(fId, WM_QUIT, 0, 0);
640  ::CloseHandle(fHandle);
641  }
642  fHandle = 0;
643 }
644 
645 ////////////////////////////////////////////////////////////////////////////////
646 /// lock message queue
647 
648 void TGWin32MainThread::LockMSG()
649 {
650  if (fMessageMutex) ::EnterCriticalSection(fMessageMutex);
651 }
652 
653 ////////////////////////////////////////////////////////////////////////////////
654 /// unlock message queue
655 
656 void TGWin32MainThread::UnlockMSG()
657 {
658  if (fMessageMutex) ::LeaveCriticalSection(fMessageMutex);
659 }
660 
661 ///////////////////////////////////////////////////////////////////////////////
662 class TGWin32RefreshTimer : public TTimer {
663 
664 public:
665  TGWin32RefreshTimer() : TTimer(10, kTRUE) { if (gSystem) gSystem->AddTimer(this); }
666  ~TGWin32RefreshTimer() { if (gSystem) gSystem->RemoveTimer(this); }
667  Bool_t Notify()
668  {
669  Reset();
670  MSG msg;
671 
672  while (::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE)) {
673  ::PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE);
674  if (!gVirtualX)
675  Sleep(200); // avoid start-up race
676  if (gVirtualX)
677  ((TGWin32*)gVirtualX)->GUIThreadMessageFunc(&msg);
678  }
679  return kFALSE;
680  }
681 };
682 /*
683 ////////////////////////////////////////////////////////////////////////////////
684 /// thread for processing windows messages (aka Main/Server thread)
685 
686 static DWORD WINAPI MessageProcessingLoop(void *p)
687 {
688  MSG msg;
689  Int_t erret;
690  Bool_t endLoop = kFALSE;
691  TGWin32RefreshTimer *refersh = 0;
692 
693  // force to create message queue
694  ::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
695 
696  // periodically we refresh windows
697  // Don't create refresh timer if the application has been created inside PVSS
698  if (gApplication) {
699  TString arg = gSystem->BaseName(gApplication->Argv(0));
700  if (!arg.Contains("PVSS"))
701  refersh = new TGWin32RefreshTimer();
702  }
703 
704  while (!endLoop) {
705  erret = ::GetMessage(&msg, NULL, NULL, NULL);
706  if (erret <= 0) endLoop = kTRUE;
707  endLoop = MessageProcessingFunc(&msg);
708  }
709 
710  TGWin32::Instance()->CloseDisplay();
711  if (refersh)
712  delete refersh;
713 
714  // exit thread
715  if (erret == -1) {
716  erret = ::GetLastError();
717  Error("MsgLoop", "Error in GetMessage");
718  ::ExitThread(-1);
719  } else {
720  ::ExitThread(0);
721  }
722  return 0;
723 }
724 */
725 
726 Bool_t GUIThreadMessageWrapper(MSG* msg)
727 {
728  // Static wrapper for handling GUI messages.
729  // Forwards from TWinNTSystem's GUIThreadMessageProcessingLoop()
730  // to TGWin32::GUIThreadMessageFunc()
731 
732  return ((TGWin32*)gVirtualX)->GUIThreadMessageFunc(msg);
733 }
734 
735 ////////////////////////////////////////////////////////////////////////////////
736 /// constructor
737 
738 TGWin32MainThread::TGWin32MainThread()
739 {
740  fCritSec = new CRITICAL_SECTION;
741  ::InitializeCriticalSection(fCritSec);
742  fMessageMutex = new CRITICAL_SECTION;
743  ::InitializeCriticalSection(fMessageMutex);
744  fHandle = ((TWinNTSystem*)gSystem)->GetGUIThreadHandle();
745  fId = ((TWinNTSystem*)gSystem)->GetGUIThreadId();
746  ((TWinNTSystem*)gSystem)->SetGUIThreadMsgHandler(GUIThreadMessageWrapper);
747 }
748 
749 } // unnamed namespace
750 
751 ///////////////////////// TGWin32 implementation ///////////////////////////////
752 ClassImp(TGWin32);
753 
754 ////////////////////////////////////////////////////////////////////////////////
755 /// Default constructor.
756 
757 TGWin32::TGWin32(): fRefreshTimer(0)
758 {
759  fScreenNumber = 0;
760  fWindows = 0;
761  fColors = 0;
762 }
763 
764 ////////////////////////////////////////////////////////////////////////////////
765 /// Normal Constructor.
766 
767 TGWin32::TGWin32(const char *name, const char *title) : TVirtualX(name,title), fRefreshTimer(0)
768 {
769  fScreenNumber = 0;
770  fHasTTFonts = kFALSE;
771  fUseSysPointers = kFALSE;
772  fTextAlignH = 1;
773  fTextAlignV = 1;
774  fTextAlign = 7;
775  fTextMagnitude = 1;
776  fCharacterUpX = 1;
777  fCharacterUpY = 1;
778  fDrawMode = kCopy;
779  fWindows = 0;
780  fMaxNumberOfWindows = 10;
781  fXEvent = 0;
782  fFillColorModified = kFALSE;
783  fFillStyleModified = kFALSE;
784  fLineColorModified = kFALSE;
785  fPenModified = kFALSE;
786  fMarkerStyleModified = kFALSE;
787  fMarkerColorModified = kFALSE;
788 
789  fWindows = (XWindow_t*) TStorage::Alloc(fMaxNumberOfWindows*sizeof(XWindow_t));
790  for (int i = 0; i < fMaxNumberOfWindows; i++) fWindows[i].open = 0;
791 
792  fColors = new TExMap;
793 
794  if (gApplication) {
795  TString arg = gSystem->BaseName(gApplication->Argv(0));
796  if (!arg.Contains("PVSS"))
797  fRefreshTimer = new TGWin32RefreshTimer();
798  } else {
799  fRefreshTimer = new TGWin32RefreshTimer();
800  }
801 
802  // initialize GUI thread and proxy objects
803  if (!gROOT->IsBatch() && !gMainThread) {
804  gMainThread = new TGWin32MainThread();
805  TGWin32ProxyBase::fgMainThreadId = ::GetCurrentThreadId(); // gMainThread->fId;
806  TGWin32VirtualXProxy::fgRealObject = this;
807  gPtr2VirtualX = &TGWin32VirtualXProxy::ProxyObject;
808  }
809 }
810 
811 ////////////////////////////////////////////////////////////////////////////////
812 /// destructor.
813 
814 TGWin32::~TGWin32()
815 {
816  CloseDisplay();
817  if (fRefreshTimer)
818  delete fRefreshTimer;
819  if (!fColors) return;
820  Long64_t key, value;
821  TExMapIter it(fColors);
822  while (it.Next(key, value)) {
823  XColor_t *col = (XColor_t *) value;
824  delete col;
825  }
826  delete fColors;
827 }
828 
829 ////////////////////////////////////////////////////////////////////////////////
830 /// Windows timer handling events while moving/resizing windows
831 
832 VOID CALLBACK MyTimerProc(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime)
833 {
834  gSystem->ProcessEvents();
835  //gVirtualX->UpdateWindow(1); // cause problems with OpenGL in pad...
836 }
837 
838 ////////////////////////////////////////////////////////////////////////////////
839 /// Message processing function for the GUI thread.
840 /// Kicks in once TGWin32 becomes active, and "replaces" the dummy one
841 /// in TWinNTSystem; see TWinNTSystem.cxx's GUIThreadMessageProcessingLoop().
842 
843 Bool_t TGWin32::GUIThreadMessageFunc(MSG* msg)
844 {
845  Bool_t ret = kFALSE;
846  static Int_t m_timer = 0;
847 
848  if ( (msg->message == WM_NCLBUTTONDOWN) ) {
849  if (m_timer == 0)
850  m_timer = SetTimer(NULL, 1, 20, (TIMERPROC) MyTimerProc);
851  }
852  else if (msg->message == WM_NCMOUSELEAVE ) {
853  if (m_timer) {
854  KillTimer(NULL, m_timer);
855  }
856  m_timer = 0;
857  }
858 
859  if (msg->message == TGWin32ProxyBase::fgPostMessageId) {
860  if (msg->wParam) {
861  TGWin32ProxyBase *proxy = (TGWin32ProxyBase*)msg->wParam;
862  proxy->ExecuteCallBack(kTRUE);
863  } else {
864  ret = kTRUE;
865  }
866  } else if (msg->message == TGWin32ProxyBase::fgPingMessageId) {
867  TGWin32ProxyBase::GlobalUnlock();
868  } else {
869  //if ( (msg->message >= WM_NCMOUSEMOVE) &&
870  // (msg->message <= WM_NCMBUTTONDBLCLK) ) {
871  // TGWin32ProxyBase::GlobalLock();
872  //}
873  TGWin32MainThread::LockMSG();
874  TranslateMessage(msg);
875  DispatchMessage(msg);
876  TGWin32MainThread::UnlockMSG();
877  }
878  return ret;
879 }
880 
881 ////////////////////////////////////////////////////////////////////////////////
882 /// returns kTRUE if we are inside cmd/server thread
883 
884 Bool_t TGWin32::IsCmdThread() const
885 {
886 #ifdef OLD_THREAD_IMPLEMENTATION
887  return ((::GetCurrentThreadId() == TGWin32ProxyBase::fgMainThreadId) ||
888  (::GetCurrentThreadId() == TGWin32ProxyBase::fgUserThreadId));
889 #else
890  return kTRUE;
891 #endif
892 }
893 
894 ////////////////////////////////////////////////////////////////////////////////
895 /// close display (terminate server/gMainThread thread)
896 
897 void TGWin32::CloseDisplay()
898 {
899  // disable any processing while exiting
900  TGWin32ProxyBase::GlobalLock();
901 
902  // terminate server thread
903  gPtr2VirtualX = 0;
904  gVirtualX = TGWin32VirtualXProxy::RealObject();
905 
906  // The lock above does not work, so at least
907  // minimize the risk
908  TGWin32MainThread *delThread = gMainThread;
909  if (gMainThread) {
910  gMainThread = 0;
911  delete delThread;
912  }
913 
914  TGWin32ProxyBase::fgMainThreadId = 0;
915 
916  // terminate ROOT logo splash thread
917  TWin32SplashThread *delSplash = gSplash;
918  if (gSplash) {
919  gSplash = 0;
920  delete delSplash;
921  }
922 
923  if (fWindows) TStorage::Dealloc(fWindows);
924  fWindows = 0;
925 
926  if (fXEvent) gdk_event_free((GdkEvent*)fXEvent);
927 
928  TGWin32ProxyBase::GlobalUnlock();
929 
930  gROOT->SetBatch(kTRUE); // no GUI is possible
931 }
932 
933 ////////////////////////////////////////////////////////////////////////////////
934 ///
935 
936 void TGWin32::Lock()
937 {
938  if (gMainThread && gMainThread->fCritSec) ::EnterCriticalSection(gMainThread->fCritSec);
939 }
940 
941 ////////////////////////////////////////////////////////////////////////////////
942 ///
943 
944 void TGWin32::Unlock()
945 {
946  if (gMainThread && gMainThread->fCritSec) ::LeaveCriticalSection(gMainThread->fCritSec);
947 }
948 
949 ////////////////////////////////////////////////////////////////////////////////
950 /// Initialize Win32 system. Returns kFALSE in case of failure.
951 
952 Bool_t TGWin32::Init(void *display)
953 {
954  if (!gdk_initialized) {
955  if (!gdk_init_check(NULL, NULL)) return kFALSE;
956  gdk_initialized = true;
957  }
958 
959  if (!gClipboardAtom) {
960  gClipboardAtom = gdk_atom_intern("CLIPBOARD", kFALSE);
961  }
962 
963  return kTRUE;
964 }
965 
966 ////////////////////////////////////////////////////////////////////////////////
967 /// Open the display. Return -1 if the opening fails, 0 when ok.
968 
969 Int_t TGWin32::OpenDisplay(const char *dpyName)
970 {
971  GdkPixmap *pixmp1, *pixmp2;
972  GdkColor fore, back;
973  GdkColor color;
974  GdkGCValues gcvals;
975  int i;
976 
977  if (!Init((void*)dpyName)) {
978  return -1;
979  }
980 
981  if (gDebug <= 4) {
982  gdk_debug_level = gDebug;
983  } else {
984  gdk_debug_level = 0;
985  }
986 
987  fore.red = fore.green = fore.blue = 0;
988  back.red = back.green = back.blue = 0;
989  color.red = color.green = color.blue = 0;
990 
991  fScreenNumber = 0; //DefaultScreen(fDisplay);
992  fVisual = gdk_visual_get_best();
993  fColormap = gdk_colormap_get_system();
994  fDepth = gdk_visual_get_best_depth();
995 
996  GetColor(1).fDefined = kTRUE; // default foreground
997  gdk_color_black((GdkColormap *)fColormap, &GetColor(1).color);
998 
999  GetColor(0).fDefined = kTRUE; // default background
1000  gdk_color_white((GdkColormap *)fColormap, &GetColor(0).color);
1001 
1002  // Create primitives graphic contexts
1003  for (i = 0; i < kMAXGC; i++) {
1004  gGClist[i] = gdk_gc_new(GDK_ROOT_PARENT());
1005  gdk_gc_set_foreground(gGClist[i], &GetColor(1).color);
1006  gdk_gc_set_background(gGClist[i], &GetColor(0).color);
1007  }
1008 
1009  gGCline = gGClist[0]; // PolyLines
1010  gGCmark = gGClist[1]; // PolyMarker
1011  gGCfill = gGClist[2]; // Fill areas
1012  gGCtext = gGClist[3]; // Text
1013  gGCinvt = gGClist[4]; // Inverse text
1014  gGCdash = gGClist[5]; // Dashed lines
1015  gGCpxmp = gGClist[6]; // Pixmap management
1016 
1017  gdk_gc_get_values(gGCtext, &gcvals);
1018  gdk_gc_set_foreground(gGCinvt, &gcvals.background);
1019  gdk_gc_set_background(gGCinvt, &gcvals.foreground);
1020 
1021  // Create input echo graphic context
1022  GdkGCValues echov;
1023  gdk_color_black(fColormap, &echov.foreground); // = BlackPixel(fDisplay, fScreenNumber);
1024  gdk_color_white(fColormap, &echov.background); // = WhitePixel(fDisplay, fScreenNumber);
1025  echov.function = GDK_INVERT;
1026  echov.subwindow_mode = GDK_CLIP_BY_CHILDREN;
1027  gGCecho =
1028  gdk_gc_new_with_values((GdkWindow *) GDK_ROOT_PARENT(), &echov,
1029  (GdkGCValuesMask) (GDK_GC_FOREGROUND |
1030  GDK_GC_BACKGROUND |
1031  GDK_GC_FUNCTION |
1032  GDK_GC_SUBWINDOW));
1033  // Create a null cursor
1034  pixmp1 = gdk_bitmap_create_from_data(GDK_ROOT_PARENT(),
1035  (const char *)null_cursor_bits, 16,16);
1036 
1037  pixmp2 = gdk_bitmap_create_from_data(GDK_ROOT_PARENT(),
1038  (const char *)null_cursor_bits, 16, 16);
1039 
1040  gNullCursor = gdk_cursor_new_from_pixmap((GdkDrawable *)pixmp1, (GdkDrawable *)pixmp2,
1041  &fore, &back, 0, 0);
1042  // Create cursors
1043  if (gEnv->GetValue("Win32.UseSysPointers", 0)) {
1044  fUseSysPointers = kTRUE;
1045  fCursors[kBottomLeft] = gdk_syscursor_new((ULong_t)IDC_SIZENESW);
1046  fCursors[kBottomRight] = gdk_syscursor_new((ULong_t)IDC_SIZENWSE);
1047  fCursors[kTopLeft] = gdk_syscursor_new((ULong_t)IDC_SIZENWSE);
1048  fCursors[kTopRight] = gdk_syscursor_new((ULong_t)IDC_SIZENESW);
1049  fCursors[kBottomSide] = gdk_syscursor_new((ULong_t)IDC_SIZENS);
1050  fCursors[kLeftSide] = gdk_syscursor_new((ULong_t)IDC_SIZEWE);
1051  fCursors[kTopSide] = gdk_syscursor_new((ULong_t)IDC_SIZENS);
1052  fCursors[kRightSide] = gdk_syscursor_new((ULong_t)IDC_SIZEWE);
1053  fCursors[kMove] = gdk_syscursor_new((ULong_t)IDC_SIZEALL);
1054  fCursors[kCross] =gdk_syscursor_new((ULong_t)IDC_CROSS);
1055  fCursors[kArrowHor] = gdk_syscursor_new((ULong_t)IDC_SIZEWE);
1056  fCursors[kArrowVer] = gdk_syscursor_new((ULong_t)IDC_SIZENS);
1057  fCursors[kHand] = gdk_syscursor_new((ULong_t)IDC_HAND);
1058  fCursors[kPointer] = gdk_syscursor_new((ULong_t)IDC_ARROW);
1059  fCursors[kCaret] = gdk_syscursor_new((ULong_t)IDC_IBEAM);
1060  fCursors[kWatch] = gdk_syscursor_new((ULong_t)IDC_WAIT);
1061  fCursors[kNoDrop] = gdk_syscursor_new((ULong_t)IDC_NO);
1062  }
1063  else {
1064  fUseSysPointers = kFALSE;
1065  fCursors[kBottomLeft] = gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER);
1066  fCursors[kBottomRight] = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER);
1067  fCursors[kTopLeft] = gdk_cursor_new(GDK_TOP_LEFT_CORNER);
1068  fCursors[kTopRight] = gdk_cursor_new(GDK_TOP_RIGHT_CORNER);
1069  fCursors[kBottomSide] = gdk_cursor_new(GDK_BOTTOM_SIDE);
1070  fCursors[kLeftSide] = gdk_cursor_new(GDK_LEFT_SIDE);
1071  fCursors[kTopSide] = gdk_cursor_new(GDK_TOP_SIDE);
1072  fCursors[kRightSide] = gdk_cursor_new(GDK_RIGHT_SIDE);
1073  fCursors[kMove] = gdk_cursor_new(GDK_FLEUR);
1074  fCursors[kCross] =gdk_cursor_new(GDK_CROSSHAIR);
1075  fCursors[kArrowHor] = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
1076  fCursors[kArrowVer] = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
1077  fCursors[kHand] = gdk_cursor_new(GDK_HAND2);
1078  fCursors[kPointer] = gdk_cursor_new(GDK_LEFT_PTR);
1079  fCursors[kCaret] = gdk_cursor_new(GDK_XTERM);
1080  //fCursors[kWatch] = gdk_cursor_new(GDK_WATCH);
1081  fCursors[kWatch] = gdk_cursor_new(GDK_BUSY);
1082  fCursors[kNoDrop] = gdk_cursor_new(GDK_PIRATE);
1083  }
1084  fCursors[kRotate] = gdk_cursor_new(GDK_EXCHANGE);
1085  fCursors[kArrowRight] = gdk_cursor_new(GDK_ARROW);
1086 
1087  // Setup color information
1088  fRedDiv = fGreenDiv = fBlueDiv = fRedShift = fGreenShift = fBlueShift = -1;
1089 
1090  if ( gdk_visual_get_best_type() == GDK_VISUAL_TRUE_COLOR) {
1091  int i;
1092  for (i = 0; i < int(sizeof(fVisual->blue_mask)*kBitsPerByte); i++) {
1093  if (fBlueShift == -1 && ((fVisual->blue_mask >> i) & 1)) {
1094  fBlueShift = i;
1095  }
1096  if ((fVisual->blue_mask >> i) == 1) {
1097  fBlueDiv = sizeof(UShort_t)*kBitsPerByte - i - 1 + fBlueShift;
1098  break;
1099  }
1100  }
1101  for (i = 0; i < int(sizeof(fVisual->green_mask)*kBitsPerByte); i++) {
1102  if (fGreenShift == -1 && ((fVisual->green_mask >> i) & 1)) {
1103  fGreenShift = i;
1104  }
1105  if ((fVisual->green_mask >> i) == 1) {
1106  fGreenDiv = sizeof(UShort_t)*kBitsPerByte - i - 1 + fGreenShift;
1107  break;
1108  }
1109  }
1110  for (i = 0; i < int(sizeof(fVisual->red_mask)*kBitsPerByte); i++) {
1111  if (fRedShift == -1 && ((fVisual->red_mask >> i) & 1)) {
1112  fRedShift = i;
1113  }
1114  if ((fVisual->red_mask >> i) == 1) {
1115  fRedDiv = sizeof(UShort_t)*kBitsPerByte - i - 1 + fRedShift;
1116  break;
1117  }
1118  }
1119  }
1120 
1121  SetName("Win32TTF");
1122  SetTitle("ROOT interface to Win32 with TrueType fonts");
1123 
1124  if (!TTF::IsInitialized()) TTF::Init();
1125 
1126  if (fDepth > 8) {
1127  TTF::SetSmoothing(kTRUE);
1128  } else {
1129  TTF::SetSmoothing(kFALSE);
1130  }
1131 
1132  TGWin32VirtualXProxy::fMaxResponseTime = 1000;
1133  fHasTTFonts = kTRUE;
1134  return 0;
1135 }
1136 
1137 ////////////////////////////////////////////////////////////////////////////////
1138 /// Allocate color in colormap. If we are on an <= 8 plane machine
1139 /// we will use XAllocColor. If we are on a >= 15 (15, 16 or 24) plane
1140 /// true color machine we will calculate the pixel value using:
1141 /// for 15 and 16 bit true colors have 6 bits precision per color however
1142 /// only the 5 most significant bits are used in the color index.
1143 /// Except for 16 bits where green uses all 6 bits. I.e.:
1144 /// 15 bits = rrrrrgggggbbbbb
1145 /// 16 bits = rrrrrggggggbbbbb
1146 /// for 24 bits each r, g and b are represented by 8 bits.
1147 ///
1148 /// Since all colors are set with a max of 65535 (16 bits) per r, g, b
1149 /// we just right shift them by 10, 11 and 10 bits for 16 planes, and
1150 /// (10, 10, 10 for 15 planes) and by 8 bits for 24 planes.
1151 /// Returns kFALSE in case color allocation failed.
1152 
1153 Bool_t TGWin32::AllocColor(GdkColormap *cmap, GdkColor *color)
1154 {
1155  if (fRedDiv == -1) {
1156  if ( gdk_color_alloc((GdkColormap *)cmap, (GdkColor *)color) ) return kTRUE;
1157  } else {
1158  color->pixel = (color->red >> fRedDiv) << fRedShift |
1159  (color->green >> fGreenDiv) << fGreenShift |
1160  (color->blue >> fBlueDiv) << fBlueShift;
1161  return kTRUE;
1162  }
1163 
1164  return kFALSE;
1165 }
1166 
1167 ////////////////////////////////////////////////////////////////////////////////
1168 /// Returns the current RGB value for the pixel in the XColor structure.
1169 
1170 void TGWin32::QueryColors(GdkColormap *cmap, GdkColor *color, Int_t ncolors)
1171 {
1172  ULong_t r, g, b;
1173 
1174  if (fRedDiv == -1) {
1175  GdkColorContext *cc = gdk_color_context_new(gdk_visual_get_system(), cmap);
1176  gdk_color_context_query_colors(cc, color, ncolors);
1177  gdk_color_context_free(cc);
1178  } else {
1179  for (Int_t i = 0; i < ncolors; i++) {
1180  r = (color[i].pixel & fVisual->red_mask) >> fRedShift;
1181  color[i].red = UShort_t(r*kBIGGEST_RGB_VALUE/(fVisual->red_mask >> fRedShift));
1182 
1183  g = (color[i].pixel & fVisual->green_mask) >> fGreenShift;
1184  color[i].green = UShort_t(g*kBIGGEST_RGB_VALUE/(fVisual->green_mask >> fGreenShift));
1185 
1186  b = (color[i].pixel & fVisual->blue_mask) >> fBlueShift;
1187  color[i].blue = UShort_t(b*kBIGGEST_RGB_VALUE/(fVisual->blue_mask >> fBlueShift));
1188  }
1189  }
1190 }
1191 
1192 ////////////////////////////////////////////////////////////////////////////////
1193 /// Compute alignment variables. The alignment is done on the horizontal string
1194 /// then the rotation is applied on the alignment variables.
1195 /// SetRotation and LayoutGlyphs should have been called before.
1196 
1197 void TGWin32::Align(void)
1198 {
1199  EAlign align = (EAlign) fTextAlign;
1200 
1201  // vertical alignment
1202  if (align == kTLeft || align == kTCenter || align == kTRight) {
1203  fAlign.y = TTF::GetAscent();
1204  } else if (align == kMLeft || align == kMCenter || align == kMRight) {
1205  fAlign.y = TTF::GetAscent()/2;
1206  } else {
1207  fAlign.y = 0;
1208  }
1209  // horizontal alignment
1210  if (align == kTRight || align == kMRight || align == kBRight) {
1211  fAlign.x = TTF::GetWidth();
1212  } else if (align == kTCenter || align == kMCenter || align == kBCenter) {
1213  fAlign.x = TTF::GetWidth()/2;
1214  } else {
1215  fAlign.x = 0;
1216  }
1217 
1218  FT_Vector_Transform(&fAlign, TTF::GetRotMatrix());
1219  fAlign.x = fAlign.x >> 6;
1220  fAlign.y = fAlign.y >> 6;
1221 }
1222 
1223 ////////////////////////////////////////////////////////////////////////////////
1224 /// Draw FT_Bitmap bitmap to xim image at position bx,by using specified
1225 /// foreground color.
1226 
1227 void TGWin32::DrawImage(FT_Bitmap *source, ULong_t fore, ULong_t back,
1228  GdkImage *xim, Int_t bx, Int_t by)
1229 {
1230  UChar_t d = 0, *s = source->buffer;
1231 
1232  if (TTF::GetSmoothing()) {
1233 
1234  static GdkColor col[5];
1235  GdkColor *bcol = 0, *bc;
1236  Int_t x, y;
1237 
1238  // background kClear, i.e. transparent, we take as background color
1239  // the average of the rgb values of all pixels covered by this character
1240  if (back == (ULong_t) -1 && (UInt_t)source->width) {
1241  ULong_t r, g, b;
1242  Int_t dots, dotcnt;
1243  const Int_t maxdots = 50000;
1244 
1245  dots = Int_t(source->width * source->rows);
1246  dots = dots > maxdots ? maxdots : dots;
1247  bcol = new GdkColor[dots];
1248  if (!bcol) return;
1249 
1250  bc = bcol;
1251  dotcnt = 0;
1252  for (y = 0; y < (int) source->rows; y++) {
1253  for (x = 0; x < (int) source->width; x++, bc++) {
1254  bc->pixel = GetPixelImage((Drawable_t)xim, bx + x, by + y);
1255  if (++dotcnt >= maxdots) break;
1256  }
1257  }
1258  QueryColors(fColormap, bcol, dots);
1259  r = g = b = 0;
1260  bc = bcol;
1261  dotcnt = 0;
1262  for (y = 0; y < (int) source->rows; y++) {
1263  for (x = 0; x < (int) source->width; x++, bc++) {
1264  r += bc->red;
1265  g += bc->green;
1266  b += bc->blue;
1267  if (++dotcnt >= maxdots) break;
1268  }
1269  }
1270  if (dots != 0) {
1271  r /= dots;
1272  g /= dots;
1273  b /= dots;
1274  }
1275  bc = &col[0];
1276  if (bc->red == r && bc->green == g && bc->blue == b) {
1277  bc->pixel = back;
1278  } else {
1279  bc->pixel = ~back;
1280  bc->red = (UShort_t) r;
1281  bc->green = (UShort_t) g;
1282  bc->blue = (UShort_t) b;
1283  }
1284  }
1285  delete [] bcol;
1286 
1287  // if fore or background have changed from previous character
1288  // recalculate the 3 smooting colors (interpolation between fore-
1289  // and background colors)
1290  if (fore != col[4].pixel || back != col[0].pixel) {
1291  col[4].pixel = fore;
1292  if (back != (ULong_t) -1) {
1293  col[3].pixel = back;
1294  QueryColors(fColormap, &col[3], 2);
1295  col[0] = col[3];
1296  } else {
1297  QueryColors(fColormap, &col[4], 1);
1298  }
1299 
1300  // interpolate between fore and backgound colors
1301  for (x = 3; x > 0; x--) {
1302  col[x].red = (col[4].red *x + col[0].red *(4-x)) /4;
1303  col[x].green = (col[4].green*x + col[0].green*(4-x)) /4;
1304  col[x].blue = (col[4].blue *x + col[0].blue *(4-x)) /4;
1305  if (!AllocColor(fColormap, &col[x])) {
1306  Warning("DrawImage", "cannot allocate smoothing color");
1307  col[x].pixel = col[x+1].pixel;
1308  }
1309  }
1310  }
1311 
1312  // put smoothed character, character pixmap values are an index
1313  // into the 5 colors used for aliasing (4 = foreground, 0 = background)
1314  for (y = 0; y < (int) source->rows; y++) {
1315  for (x = 0; x < (int) source->width; x++) {
1316  d = *s++ & 0xff;
1317  d = ((d + 10) * 5) / 256;
1318  if (d > 4) d = 4;
1319  if (d && x < (int) source->width) {
1320  ULong_t p = col[d].pixel;
1321  PutPixel((Drawable_t)xim, bx + x, by + y, p);
1322  }
1323  }
1324  }
1325  } else {
1326  // no smoothing, just put character using foreground color
1327  UChar_t* row=s;
1328  for (int y = 0; y < (int) source->rows; y++) {
1329  int n = 0;
1330  s = row;
1331  for (int x = 0; x < (int) source->width; x++) {
1332  if (n == 0) d = *s++;
1333  if (TESTBIT(d,7-n)) {
1334  PutPixel((Drawable_t)xim, bx + x, by + y, fore);
1335  }
1336  if (++n == (int) kBitsPerByte) n = 0;
1337  }
1338  row += source->pitch;
1339  }
1340  }
1341 }
1342 
1343 ////////////////////////////////////////////////////////////////////////////////
1344 /// Draw text using TrueType fonts. If TrueType fonts are not available the
1345 /// text is drawn with TGWin32::DrawText.
1346 
1347 void TGWin32::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn,
1348  const char *text, ETextMode mode)
1349 {
1350  if (!TTF::IsInitialized()) TTF::Init();
1351  TTF::SetRotationMatrix(angle);
1352  TTF::PrepareString(text);
1353  TTF::LayoutGlyphs();
1354  Align();
1355  RenderString(x, y, mode);
1356 }
1357 
1358 ////////////////////////////////////////////////////////////////////////////////
1359 /// Draw text using TrueType fonts. If TrueType fonts are not available the
1360 /// text is drawn with TGWin32::DrawText.
1361 
1362 void TGWin32::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn,
1363  const wchar_t *text, ETextMode mode)
1364 {
1365  if (!TTF::IsInitialized()) TTF::Init();
1366  TTF::SetRotationMatrix(angle);
1367  TTF::PrepareString(text);
1368  TTF::LayoutGlyphs();
1369  Align();
1370  RenderString(x, y, mode);
1371 }
1372 
1373 ////////////////////////////////////////////////////////////////////////////////
1374 /// Get the background of the current window in an XImage.
1375 
1376 GdkImage *TGWin32::GetBackground(Int_t x, Int_t y, UInt_t w, UInt_t h)
1377 {
1378  Window_t cws = GetCurrentWindow();
1379  UInt_t width;
1380  UInt_t height;
1381  Int_t xy;
1382  gVirtualX->GetWindowSize(cws, xy, xy, width, height);
1383 
1384  if (x < 0) {
1385  w += x;
1386  x = 0;
1387  }
1388  if (y < 0) {
1389  h += y;
1390  y = 0;
1391  }
1392 
1393  if (x+w > width) w = width - x;
1394  if (y+h > height) h = height - y;
1395 
1396  return gdk_image_get((GdkDrawable*)cws, x, y, w, h);
1397 }
1398 
1399 ////////////////////////////////////////////////////////////////////////////////
1400 /// Test if there is really something to render
1401 
1402 Bool_t TGWin32::IsVisible(Int_t x, Int_t y, UInt_t w, UInt_t h)
1403 {
1404  Window_t cws = GetCurrentWindow();
1405  UInt_t width;
1406  UInt_t height;
1407  Int_t xy;
1408  gVirtualX->GetWindowSize(cws, xy, xy, width, height);
1409 
1410  // If w or h is 0, very likely the string is only blank characters
1411  if ((int)w == 0 || (int)h == 0) return kFALSE;
1412 
1413  // If string falls outside window, there is probably no need to draw it.
1414  if (x + (int)w <= 0 || x >= (int)width) return kFALSE;
1415  if (y + (int)h <= 0 || y >= (int)height) return kFALSE;
1416 
1417  return kTRUE;
1418 }
1419 
1420 ////////////////////////////////////////////////////////////////////////////////
1421 /// Perform the string rendering in the pad.
1422 /// LayoutGlyphs should have been called before.
1423 
1424 void TGWin32::RenderString(Int_t x, Int_t y, ETextMode mode)
1425 {
1426  TTF::TTGlyph* glyph = TTF::GetGlyphs();
1427  GdkGCValues gcvals;
1428 
1429  // compute the size and position of the XImage that will contain the text
1430  Int_t Xoff = 0; if (TTF::GetBox().xMin < 0) Xoff = -TTF::GetBox().xMin;
1431  Int_t Yoff = 0; if (TTF::GetBox().yMin < 0) Yoff = -TTF::GetBox().yMin;
1432  Int_t w = TTF::GetBox().xMax + Xoff;
1433  Int_t h = TTF::GetBox().yMax + Yoff;
1434  Int_t x1 = x-Xoff-fAlign.x;
1435  Int_t y1 = y+Yoff+fAlign.y-h;
1436 
1437  if (!IsVisible(x1, y1, w, h)) {
1438  return;
1439  }
1440 
1441  // create the XImage that will contain the text
1442  UInt_t depth = fDepth;
1443  GdkImage *xim = gdk_image_new(GDK_IMAGE_SHARED, gdk_visual_get_best(), w, h);
1444 
1445  // use malloc since Xlib will use free() in XDestroyImage
1446 // xim->data = (char *) malloc(xim->bytes_per_line * h);
1447 // memset(xim->data, 0, xim->bytes_per_line * h);
1448 
1449  ULong_t pixel;
1450  ULong_t bg;
1451 
1452  gdk_gc_get_values((GdkGC*)GetGC(3), &gcvals);
1453 
1454  // get the background
1455  if (mode == kClear) {
1456  // if mode == kClear we need to get an image of the background
1457  GdkImage *bim = GetBackground(x1, y1, w, h);
1458  if (!bim) {
1459  Error("DrawText", "error getting background image");
1460  return;
1461  }
1462 
1463  // and copy it into the text image
1464  Int_t xo = 0, yo = 0;
1465  if (x1 < 0) xo = -x1;
1466  if (y1 < 0) yo = -y1;
1467 
1468  for (int yp = 0; yp < (int) bim->height; yp++) {
1469  for (int xp = 0; xp < (int) bim->width; xp++) {
1470  pixel = GetPixelImage((Drawable_t)bim, xp, yp);
1471  PutPixel((Drawable_t)xim, xo+xp, yo+yp, pixel);
1472  }
1473  }
1474 
1475  gdk_image_unref((GdkImage *)bim);
1476 
1477  bg = (ULong_t) -1;
1478  } else {
1479  // if mode == kOpaque its simple, we just draw the background
1480 
1481  GdkImage *bim = GetBackground(x1, y1, w, h);
1482  if (!bim) {
1483  pixel = gcvals.background.pixel;
1484  } else {
1485  pixel = GetPixelImage((Drawable_t)bim, 0, 0);
1486  }
1487  Int_t xo = 0, yo = 0;
1488  if (x1 < 0) xo = -x1;
1489  if (y1 < 0) yo = -y1;
1490 
1491  for (int yp = 0; yp < h; yp++) {
1492  for (int xp = 0; xp < (int) w; xp++) {
1493  PutPixel((Drawable_t)xim, xo+xp, yo+yp, pixel);
1494  }
1495  }
1496  if (bim) {
1497  gdk_image_unref((GdkImage *)bim);
1498  bg = (ULong_t) -1;
1499  } else {
1500  bg = pixel;
1501  }
1502  }
1503 
1504  // paint the glyphs in the XImage
1505  glyph = TTF::GetGlyphs();
1506  for (int n = 0; n < TTF::GetNumGlyphs(); n++, glyph++) {
1507  if (FT_Glyph_To_Bitmap(&glyph->fImage,
1508  TTF::GetSmoothing() ? ft_render_mode_normal
1509  : ft_render_mode_mono,
1510  0, 1 )) continue;
1511  FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph->fImage;
1512  FT_Bitmap* source = &bitmap->bitmap;
1513  Int_t bx, by;
1514 
1515  bx = bitmap->left+Xoff;
1516  by = h - bitmap->top-Yoff;
1517  DrawImage(source, gcvals.foreground.pixel, bg, xim, bx, by);
1518  }
1519 
1520  // put the Ximage on the screen
1521  Window_t cws = GetCurrentWindow();
1522  gdk_draw_image((GdkDrawable *)cws, GetGC(6), xim, 0, 0, x1, y1, w, h);
1523 
1524  gdk_image_unref(xim);
1525 }
1526 
1527 ////////////////////////////////////////////////////////////////////////////////
1528 /// Set specified font.
1529 
1530 void TGWin32::SetTextFont(Font_t fontnumber)
1531 {
1532  fTextFont = fontnumber;
1533  TTF::SetTextFont(fontnumber);
1534 }
1535 
1536 ////////////////////////////////////////////////////////////////////////////////
1537 /// Set text font to specified name.
1538 /// mode : loading flag
1539 /// mode=0 : search if the font exist (kCheck)
1540 /// mode=1 : search the font and load it if it exists (kLoad)
1541 /// font : font name
1542 ///
1543 /// Set text font to specified name. This function returns 0 if
1544 /// the specified font is found, 1 if not.
1545 
1546 Int_t TGWin32::SetTextFont(char *fontname, ETextSetMode mode)
1547 {
1548  return TTF::SetTextFont(fontname);
1549 }
1550 
1551 ////////////////////////////////////////////////////////////////////////////////
1552 /// Set current text size.
1553 
1554 void TGWin32::SetTextSize(Float_t textsize)
1555 {
1556  fTextSize = textsize;
1557  TTF::SetTextSize(textsize);
1558 }
1559 
1560 ////////////////////////////////////////////////////////////////////////////////
1561 /// Clear current window.
1562 
1563 void TGWin32::ClearWindow()
1564 {
1565  if (!fWindows) return;
1566 
1567  if (!gCws->ispixmap && !gCws->double_buffer) {
1568  gdk_window_set_background(gCws->drawing, (GdkColor *) & GetColor(0).color);
1569  gdk_window_clear(gCws->drawing);
1570  GdiFlush();
1571  } else {
1572  SetColor(gGCpxmp, 0);
1573  gdk_win32_draw_rectangle(gCws->drawing, gGCpxmp, 1,
1574  0, 0, gCws->width, gCws->height);
1575  SetColor(gGCpxmp, 1);
1576  }
1577 }
1578 
1579 ////////////////////////////////////////////////////////////////////////////////
1580 /// Delete current pixmap.
1581 
1582 void TGWin32::ClosePixmap()
1583 {
1584  CloseWindow1();
1585 }
1586 
1587 ////////////////////////////////////////////////////////////////////////////////
1588 /// Delete current window.
1589 
1590 void TGWin32::CloseWindow()
1591 {
1592  CloseWindow1();
1593 }
1594 
1595 ////////////////////////////////////////////////////////////////////////////////
1596 /// Delete current window.
1597 
1598 void TGWin32::CloseWindow1()
1599 {
1600  int wid;
1601 
1602  if (gCws->ispixmap) {
1603  gdk_pixmap_unref(gCws->window);
1604  } else {
1605  gdk_window_destroy(gCws->window, kTRUE);
1606  }
1607 
1608  if (gCws->buffer) {
1609  gdk_pixmap_unref(gCws->buffer);
1610  }
1611  if (gCws->new_colors) {
1612  gdk_colormap_free_colors((GdkColormap *) fColormap,
1613  (GdkColor *)gCws->new_colors, gCws->ncolors);
1614 
1615  delete [] gCws->new_colors;
1616  gCws->new_colors = 0;
1617  }
1618 
1619  GdiFlush();
1620  gCws->open = 0;
1621 
1622  if (!fWindows) return;
1623 
1624  // make first window in list the current window
1625  for (wid = 0; wid < fMaxNumberOfWindows; wid++) {
1626  if (fWindows[wid].open) {
1627  gCws = &fWindows[wid];
1628  return;
1629  }
1630  }
1631  gCws = 0;
1632 }
1633 
1634 ////////////////////////////////////////////////////////////////////////////////
1635 /// Copy the pixmap wid at the position xpos, ypos in the current window.
1636 
1637 void TGWin32::CopyPixmap(int wid, int xpos, int ypos)
1638 {
1639  if (!fWindows) return;
1640 
1641  gTws = &fWindows[wid];
1642  gdk_window_copy_area(gCws->drawing, gGCpxmp, xpos, ypos, gTws->drawing,
1643  0, 0, gTws->width, gTws->height);
1644  GdiFlush();
1645 }
1646 
1647 ////////////////////////////////////////////////////////////////////////////////
1648 /// Draw a box.
1649 /// mode=0 hollow (kHollow)
1650 /// mode=1 solid (kSolid)
1651 
1652 void TGWin32::DrawBox(int x1, int y1, int x2, int y2, EBoxMode mode)
1653 {
1654  if (!fWindows) return;
1655 
1656  Int_t x = TMath::Min(x1, x2);
1657  Int_t y = TMath::Min(y1, y2);
1658  Int_t w = TMath::Abs(x2 - x1);
1659  Int_t h = TMath::Abs(y2 - y1);
1660 
1661  switch (mode) {
1662 
1663  case kHollow:
1664  if (fLineColorModified) UpdateLineColor();
1665  if (fPenModified) UpdateLineStyle();
1666  gdk_win32_draw_rectangle(gCws->drawing, gGCline, 0, x, y, w, h);
1667  break;
1668 
1669  case kFilled:
1670  if (fFillStyleModified) UpdateFillStyle();
1671  if (fFillColorModified) UpdateFillColor();
1672  gdk_win32_draw_rectangle(gCws->drawing, gGCfill, 1, x, y, w, h);
1673  break;
1674 
1675  default:
1676  break;
1677  }
1678 }
1679 
1680 ////////////////////////////////////////////////////////////////////////////////
1681 /// Draw a cell array.
1682 /// x1,y1 : left down corner
1683 /// x2,y2 : right up corner
1684 /// nx,ny : array size
1685 /// ic : array
1686 ///
1687 /// Draw a cell array. The drawing is done with the pixel presicion
1688 /// if (X2-X1)/NX (or Y) is not a exact pixel number the position of
1689 /// the top rigth corner may be wrong.
1690 
1691 void TGWin32::DrawCellArray(Int_t x1, Int_t y1, Int_t x2, Int_t y2,
1692  Int_t nx, Int_t ny, Int_t *ic)
1693 {
1694  int i, j, icol, ix, iy, w, h, current_icol;
1695 
1696  if (!fWindows) return;
1697 
1698  current_icol = -1;
1699  w = TMath::Max((x2 - x1) / (nx), 1);
1700  h = TMath::Max((y1 - y2) / (ny), 1);
1701  ix = x1;
1702 
1703  if (fFillStyleModified) UpdateFillStyle();
1704  if (fFillColorModified) UpdateFillColor();
1705 
1706  for (i = 0; i < nx; i++) {
1707  iy = y1 - h;
1708  for (j = 0; j < ny; j++) {
1709  icol = ic[i + (nx * j)];
1710  if (icol != current_icol) {
1711  gdk_gc_set_foreground(gGCfill, (GdkColor *) & GetColor(icol).color);
1712  current_icol = icol;
1713  }
1714 
1715  gdk_win32_draw_rectangle(gCws->drawing, gGCfill, kTRUE, ix, iy, w, h);
1716  iy = iy - h;
1717  }
1718  ix = ix + w;
1719  }
1720 }
1721 
1722 ////////////////////////////////////////////////////////////////////////////////
1723 /// Fill area described by polygon.
1724 /// n : number of points
1725 /// xy(2,n) : list of points
1726 
1727 void TGWin32::DrawFillArea(int n, TPoint *xyt)
1728 {
1729  int i;
1730  static int lastn = 0;
1731  static GdkPoint *xy = 0;
1732 
1733  if (!fWindows) return;
1734 
1735  if (fFillStyleModified) UpdateFillStyle();
1736  if (fFillColorModified) UpdateFillColor();
1737 
1738  if (lastn!=n) {
1739  delete [] (GdkPoint *)xy;
1740  xy = new GdkPoint[n];
1741  lastn = n;
1742  }
1743  for (i = 0; i < n; i++) {
1744  xy[i].x = xyt[i].fX;
1745  xy[i].y = xyt[i].fY;
1746  }
1747 
1748  if (gFillHollow) {
1749  gdk_win32_draw_lines(gCws->drawing, gGCfill, xy, n);
1750  } else {
1751  gdk_win32_draw_polygon(gCws->drawing, gGCfill, 1, xy, n);
1752  }
1753 }
1754 
1755 ////////////////////////////////////////////////////////////////////////////////
1756 /// Draw a line.
1757 /// x1,y1 : begin of line
1758 /// x2,y2 : end of line
1759 
1760 void TGWin32::DrawLine(int x1, int y1, int x2, int y2)
1761 {
1762  if (!fWindows) return;
1763 
1764  if (fLineColorModified) UpdateLineColor();
1765  if (fPenModified) UpdateLineStyle();
1766 
1767  if (gLineStyle == GDK_LINE_SOLID) {
1768  gdk_draw_line(gCws->drawing, gGCline, x1, y1, x2, y2);
1769  } else {
1770  int i;
1771  gint8 dashes[32];
1772  for (i = 0; i < gDashSize; i++) {
1773  dashes[i] = (gint8) gDashList[i];
1774  }
1775  for (i = gDashSize; i < 32; i++) {
1776  dashes[i] = (gint8) 0;
1777  }
1778  gdk_gc_set_dashes(gGCdash, gDashOffset, dashes, gDashSize);
1779  gdk_draw_line(gCws->drawing, gGCdash, x1, y1, x2, y2);
1780  }
1781 }
1782 
1783 ////////////////////////////////////////////////////////////////////////////////
1784 /// Draw a line through all points.
1785 /// n : number of points
1786 /// xy : list of points
1787 
1788 void TGWin32::DrawPolyLine(int n, TPoint * xyt)
1789 {
1790  int i;
1791 
1792  if (!fWindows) return;
1793 
1794  Point_t *xy = new Point_t[n];
1795 
1796  for (i = 0; i < n; i++) {
1797  xy[i].fX = xyt[i].fX;
1798  xy[i].fY = xyt[i].fY;
1799  }
1800 
1801  if (fLineColorModified) UpdateLineColor();
1802  if (fPenModified) UpdateLineStyle();
1803 
1804  if (n > 1) {
1805  if (gLineStyle == GDK_LINE_SOLID) {
1806  gdk_win32_draw_lines(gCws->drawing, gGCline, (GdkPoint *)xy, n);
1807  } else {
1808  int i;
1809  gint8 dashes[32];
1810 
1811  for (i = 0; i < gDashSize; i++) {
1812  dashes[i] = (gint8) gDashList[i];
1813  }
1814  for (i = gDashSize; i < 32; i++) {
1815  dashes[i] = (gint8) 0;
1816  }
1817 
1818  gdk_gc_set_dashes(gGCdash, gDashOffset, dashes, gDashSize);
1819  gdk_win32_draw_lines(gCws->drawing, (GdkGC*)gGCdash, (GdkPoint *)xy, n);
1820 
1821  // calculate length of line to update dash offset
1822  for (i = 1; i < n; i++) {
1823  int dx = xy[i].fX - xy[i - 1].fX;
1824  int dy = xy[i].fY - xy[i - 1].fY;
1825 
1826  if (dx < 0) dx = -dx;
1827  if (dy < 0) dy = -dy;
1828  gDashOffset += dx > dy ? dx : dy;
1829  }
1830  gDashOffset %= gDashLength;
1831  }
1832  } else {
1833  gdk_win32_draw_points( gCws->drawing, gLineStyle == GDK_LINE_SOLID ?
1834  gGCline : gGCdash, (GdkPoint *)xy,1);
1835  }
1836  delete [] xy;
1837 }
1838 
1839 ////////////////////////////////////////////////////////////////////////////////
1840 /// Draw n markers with the current attributes at position x, y.
1841 /// n : number of markers to draw
1842 /// xy : x,y coordinates of markers
1843 
1844 void TGWin32::DrawPolyMarker(int n, TPoint *xyt)
1845 {
1846  int i;
1847  static int lastn = 0;
1848  static GdkPoint *xy = 0;
1849 
1850  if (!fWindows) return;
1851 
1852  if (fMarkerStyleModified) UpdateMarkerStyle();
1853  if (fMarkerColorModified) UpdateMarkerColor();
1854 
1855  if (lastn!=n) {
1856  delete [] (GdkPoint *)xy;
1857  xy = new GdkPoint[n];
1858  lastn = n;
1859  }
1860 
1861  for (i = 0; i < n; i++) {
1862  xy[i].x = xyt[i].fX;
1863  xy[i].y = xyt[i].fY;
1864  }
1865 
1866  if (gMarker.n <= 0) {
1867  gdk_win32_draw_points(gCws->drawing, gGCmark, xy, n);
1868  } else {
1869  int r = gMarker.n / 2;
1870  int m;
1871 
1872  for (m = 0; m < n; m++) {
1873  int hollow = 0;
1874  switch (gMarker.type) {
1875  int i;
1876 
1877  case 0: // hollow circle
1878  gdk_win32_draw_arc(gCws->drawing, gGCmark, kFALSE, xy[m].x-r, xy[m].y-r,
1879  gMarker.n, gMarker.n, 0, 23040);
1880  break;
1881 
1882  case 1: // filled circle
1883  gdk_win32_draw_arc(gCws->drawing, gGCmark, kTRUE, xy[m].x-r, xy[m].y-r,
1884  gMarker.n, gMarker.n, 0, 23040);
1885  break;
1886 
1887  case 2: // hollow polygon
1888  hollow = 1;
1889  case 3: // filled polygon
1890  for (i = 0; i < gMarker.n; i++) {
1891  gMarker.xy[i].x += xy[m].x;
1892  gMarker.xy[i].y += xy[m].y;
1893  }
1894  if (hollow) {
1895  gdk_win32_draw_lines(gCws->drawing, gGCmark, (GdkPoint *)gMarker.xy, gMarker.n);
1896  } else {
1897  gdk_win32_draw_polygon(gCws->drawing, gGCmark, 1, (GdkPoint *)gMarker.xy, gMarker.n);
1898  }
1899  for (i = 0; i < gMarker.n; i++) {
1900  gMarker.xy[i].x -= xy[m].x;
1901  gMarker.xy[i].y -= xy[m].y;
1902  }
1903  break;
1904 
1905  case 4: // segmented line
1906  for (i = 0; i < gMarker.n; i += 2) {
1907  gdk_draw_line(gCws->drawing, gGCmark,
1908  xy[m].x + gMarker.xy[i].x,
1909  xy[m].y + gMarker.xy[i].y,
1910  xy[m].x + gMarker.xy[i + 1].x,
1911  xy[m].y + gMarker.xy[i + 1].y);
1912  }
1913  break;
1914  }
1915  }
1916  }
1917 }
1918 
1919 ////////////////////////////////////////////////////////////////////////////////
1920 /// Return character up vector.
1921 
1922 void TGWin32::GetCharacterUp(Float_t & chupx, Float_t & chupy)
1923 {
1924  chupx = fCharacterUpX;
1925  chupy = fCharacterUpY;
1926 }
1927 
1928 ////////////////////////////////////////////////////////////////////////////////
1929 /// Return reference to internal color structure associated
1930 /// to color index cid.
1931 
1932 XColor_t &TGWin32::GetColor(Int_t cid)
1933 {
1934  XColor_t *col = (XColor_t*) fColors->GetValue(cid);
1935  if (!col) {
1936  col = new XColor_t;
1937  fColors->Add(cid, (Long_t) col);
1938  }
1939  return *col;
1940 }
1941 
1942 ////////////////////////////////////////////////////////////////////////////////
1943 /// Return current window pointer. Protected method used by TGWin32TTF.
1944 
1945 Window_t TGWin32::GetCurrentWindow() const
1946 {
1947  return (Window_t)(gCws ? gCws->drawing : 0);
1948 }
1949 
1950 ////////////////////////////////////////////////////////////////////////////////
1951 /// Return desired Graphics Context ("which" maps directly on gGCList[]).
1952 /// Protected method used by TGWin32TTF.
1953 
1954 GdkGC *TGWin32::GetGC(Int_t which) const
1955 {
1956  if (which >= kMAXGC || which < 0) {
1957  Error("GetGC", "trying to get illegal GdkGC (which = %d)", which);
1958  return 0;
1959  }
1960 
1961  return gGClist[which];
1962 }
1963 
1964 ////////////////////////////////////////////////////////////////////////////////
1965 /// Query the double buffer value for the window wid.
1966 
1967 Int_t TGWin32::GetDoubleBuffer(int wid)
1968 {
1969  if (!fWindows) return 0;
1970 
1971  gTws = &fWindows[wid];
1972 
1973  if (!gTws->open) {
1974  return -1;
1975  } else {
1976  return gTws->double_buffer;
1977  }
1978 }
1979 
1980 ////////////////////////////////////////////////////////////////////////////////
1981 /// Return position and size of window wid.
1982 /// wid : window identifier
1983 /// x,y : window position (output)
1984 /// w,h : window size (output)
1985 /// if wid < 0 the size of the display is returned
1986 
1987 void TGWin32::GetGeometry(int wid, int &x, int &y, unsigned int &w,
1988  unsigned int &h)
1989 {
1990  if (!fWindows) return;
1991 
1992  if (wid < 0) {
1993  x = 0;
1994  y = 0;
1995 
1996  w = gdk_screen_width();
1997  h = gdk_screen_height();
1998  } else {
1999  int depth;
2000  int width, height;
2001 
2002  gTws = &fWindows[wid];
2003  gdk_window_get_geometry((GdkDrawable *) gTws->window, &x, &y,
2004  &width, &height, &depth);
2005 
2006  gdk_window_get_deskrelative_origin((GdkDrawable *) gTws->window, &x, &y);
2007 
2008  if (width > 0 && height > 0) {
2009  gTws->width = width;
2010  gTws->height = height;
2011  }
2012  w = gTws->width;
2013  h = gTws->height;
2014  }
2015 }
2016 
2017 ////////////////////////////////////////////////////////////////////////////////
2018 /// Return hostname on which the display is opened.
2019 
2020 const char *TGWin32::DisplayName(const char *dpyName)
2021 {
2022  return "localhost"; //return gdk_get_display();
2023 }
2024 
2025 ////////////////////////////////////////////////////////////////////////////////
2026 /// Get maximum number of planes.
2027 
2028 void TGWin32::GetPlanes(int &nplanes)
2029 {
2030  nplanes = gdk_visual_get_best_depth();
2031 }
2032 
2033 ////////////////////////////////////////////////////////////////////////////////
2034 /// Get rgb values for color "index".
2035 
2036 void TGWin32::GetRGB(int index, float &r, float &g, float &b)
2037 {
2038  if (index == 0) {
2039  r = g = b = 1.0;
2040  } else if (index == 1) {
2041  r = g = b = 0.0;
2042  } else {
2043  XColor_t &col = GetColor(index);
2044  r = ((float) col.color.red) / ((float) kBIGGEST_RGB_VALUE);
2045  g = ((float) col.color.green) / ((float) kBIGGEST_RGB_VALUE);
2046  b = ((float) col.color.blue) / ((float) kBIGGEST_RGB_VALUE);
2047  }
2048 }
2049 
2050 ////////////////////////////////////////////////////////////////////////////////
2051 /// Return the size of a character string.
2052 /// iw : text width
2053 /// ih : text height
2054 /// mess : message
2055 
2056 void TGWin32::GetTextExtent(unsigned int &w, unsigned int &h, char *mess)
2057 {
2058  TTF::SetTextFont(gTextFont);
2059  TTF::SetTextSize(fTextSize);
2060  TTF::GetTextExtent(w, h, mess);
2061 }
2062 
2063 ////////////////////////////////////////////////////////////////////////////////
2064 /// Return the X11 window identifier.
2065 /// wid : Workstation identifier (input)
2066 
2067 Window_t TGWin32::GetWindowID(int wid)
2068 {
2069  if (!fWindows) return 0;
2070  return (Window_t) fWindows[wid].window;
2071 }
2072 
2073 ////////////////////////////////////////////////////////////////////////////////
2074 /// Move the window wid.
2075 /// wid : GdkWindow identifier.
2076 /// x : x new window position
2077 /// y : y new window position
2078 
2079 void TGWin32::MoveWindow(int wid, int x, int y)
2080 {
2081  if (!fWindows) return;
2082 
2083  gTws = &fWindows[wid];
2084  if (!gTws->open) return;
2085 
2086  gdk_window_move((GdkDrawable *) gTws->window, x, y);
2087 }
2088 
2089 ////////////////////////////////////////////////////////////////////////////////
2090 /// Open a new pixmap.
2091 /// w,h : Width and height of the pixmap.
2092 
2093 Int_t TGWin32::OpenPixmap(unsigned int w, unsigned int h)
2094 {
2095  int wval, hval;
2096  int i, wid;
2097  int ww, hh, depth;
2098  wval = w;
2099  hval = h;
2100 
2101  // Select next free window number
2102  again:
2103  for (wid = 0; wid < fMaxNumberOfWindows; wid++) {
2104  if (!fWindows[wid].open) {
2105  fWindows[wid].open = 1;
2106  gCws = &fWindows[wid];
2107  break;
2108  }
2109  }
2110  if (wid == fMaxNumberOfWindows) {
2111  int newsize = fMaxNumberOfWindows + 10;
2112  fWindows = (XWindow_t *) TStorage::ReAlloc(fWindows,
2113  newsize * sizeof(XWindow_t),
2114  fMaxNumberOfWindows *
2115  sizeof(XWindow_t));
2116 
2117  for (i = fMaxNumberOfWindows; i < newsize; i++) fWindows[i].open = 0;
2118  fMaxNumberOfWindows = newsize;
2119  goto again;
2120  }
2121 
2122  depth =gdk_visual_get_best_depth();
2123  gCws->window = (GdkPixmap *) gdk_pixmap_new(GDK_ROOT_PARENT(),wval,hval,depth);
2124  gdk_drawable_get_size((GdkDrawable *) gCws->window, &ww, &hh);
2125 
2126  for (i = 0; i < kMAXGC; i++) {
2127  gdk_gc_set_clip_mask((GdkGC *) gGClist[i], (GdkDrawable *)None);
2128  }
2129 
2130  SetColor(gGCpxmp, 0);
2131  gdk_win32_draw_rectangle(gCws->window,(GdkGC *)gGCpxmp, kTRUE,
2132  0, 0, ww, hh);
2133  SetColor(gGCpxmp, 1);
2134 
2135  // Initialise the window structure
2136  gCws->drawing = gCws->window;
2137  gCws->buffer = 0;
2138  gCws->double_buffer = 0;
2139  gCws->ispixmap = 1;
2140  gCws->clip = 0;
2141  gCws->width = wval;
2142  gCws->height = hval;
2143  gCws->new_colors = 0;
2144 
2145  return wid;
2146 }
2147 
2148 ////////////////////////////////////////////////////////////////////////////////
2149 /// Open window and return window number.
2150 /// Return -1 if window initialization fails.
2151 
2152 Int_t TGWin32::InitWindow(ULong_t win)
2153 {
2154  GdkWindowAttr attributes;
2155  unsigned long attr_mask = 0;
2156  int wid;
2157  int xval, yval;
2158  int wval, hval, depth;
2159 
2160  GdkWindow *wind = (GdkWindow *) win;
2161 
2162  gdk_window_get_geometry(wind, &xval, &yval, &wval, &hval, &depth);
2163 
2164  // Select next free window number
2165 
2166  again:
2167  for (wid = 0; wid < fMaxNumberOfWindows; wid++) {
2168  if (!fWindows[wid].open) {
2169  fWindows[wid].open = 1;
2170  fWindows[wid].double_buffer = 0;
2171  gCws = &fWindows[wid];
2172  break;
2173  }
2174  }
2175 
2176  if (wid == fMaxNumberOfWindows) {
2177  int newsize = fMaxNumberOfWindows + 10;
2178  fWindows =
2179  (XWindow_t *) TStorage::ReAlloc(fWindows,
2180  newsize * sizeof(XWindow_t),
2181  fMaxNumberOfWindows *
2182  sizeof(XWindow_t));
2183 
2184  for (int i = fMaxNumberOfWindows; i < newsize; i++) {
2185  fWindows[i].open = 0;
2186  }
2187 
2188  fMaxNumberOfWindows = newsize;
2189  goto again;
2190  }
2191  // Create window
2192  attributes.wclass = GDK_INPUT_OUTPUT;
2193  attributes.event_mask = 0L; //GDK_ALL_EVENTS_MASK;
2194  attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK |
2195  GDK_PROPERTY_CHANGE_MASK;
2196 // GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK;
2197  if (xval >= 0) {
2198  attributes.x = xval;
2199  } else {
2200  attributes.x = -1.0 * xval;
2201  }
2202 
2203  if (yval >= 0) {
2204  attributes.y = yval;
2205  } else {
2206  attributes.y = -1.0 * yval;
2207  }
2208  attributes.width = wval;
2209  attributes.height = hval;
2210  attributes.colormap = gdk_colormap_get_system();
2211  attributes.visual = gdk_window_get_visual(wind);
2212  attributes.override_redirect = TRUE;
2213 
2214  if ((attributes.y > 0) && (attributes.x > 0)) {
2215  attr_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_COLORMAP |
2216  GDK_WA_WMCLASS | GDK_WA_NOREDIR;
2217  } else {
2218  attr_mask = GDK_WA_COLORMAP | GDK_WA_WMCLASS | GDK_WA_NOREDIR;
2219  }
2220 
2221  if (attributes.visual != NULL) {
2222  attr_mask |= GDK_WA_VISUAL;
2223  }
2224  attributes.window_type = GDK_WINDOW_CHILD;
2225  gCws->window = gdk_window_new(wind, &attributes, attr_mask);
2226  HWND window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)gCws->window);
2227  ::ShowWindow(window, SW_SHOWNORMAL);
2228  ::ShowWindow(window, SW_RESTORE);
2229  ::BringWindowToTop(window);
2230 
2231  if (!fUseSysPointers) {
2232  ::SetClassLong(window, GCL_HCURSOR,
2233  (LONG)GDK_CURSOR_XID(fCursors[kPointer]));
2234  }
2235 
2236  // Initialise the window structure
2237 
2238  gCws->drawing = gCws->window;
2239  gCws->buffer = 0;
2240  gCws->double_buffer = 0;
2241  gCws->ispixmap = 0;
2242  gCws->clip = 0;
2243  gCws->width = wval;
2244  gCws->height = hval;
2245  gCws->new_colors = 0;
2246 
2247  return wid;
2248 }
2249 
2250 ////////////////////////////////////////////////////////////////////////////////
2251 /// Query pointer position.
2252 /// ix : X coordinate of pointer
2253 /// iy : Y coordinate of pointer
2254 /// (both coordinates are relative to the origin of the root window)
2255 
2256 void TGWin32::QueryPointer(int &ix, int &iy)
2257 {
2258  //GdkModifierType mask;
2259  //GdkWindow *retw = gdk_window_get_pointer((GdkWindow *) gCws->window,
2260  // &ix, &iy, &mask);
2261  POINT cpt;
2262  GetCursorPos(&cpt);
2263  ix = cpt.x;
2264  iy = cpt.y;
2265 }
2266 
2267 ////////////////////////////////////////////////////////////////////////////////
2268 /// Remove the pixmap pix.
2269 
2270 void TGWin32::RemovePixmap(GdkDrawable *pix)
2271 {
2272  gdk_pixmap_unref((GdkPixmap *)pix);
2273 }
2274 
2275 ////////////////////////////////////////////////////////////////////////////////
2276 /// Request Locator position.
2277 /// x,y : cursor position at moment of button press (output)
2278 /// ctyp : cursor type (input)
2279 /// ctyp=1 tracking cross
2280 /// ctyp=2 cross-hair
2281 /// ctyp=3 rubber circle
2282 /// ctyp=4 rubber band
2283 /// ctyp=5 rubber rectangle
2284 ///
2285 /// mode : input mode
2286 /// mode=0 request
2287 /// mode=1 sample
2288 ///
2289 /// Request locator:
2290 /// return button number 1 = left is pressed
2291 /// 2 = middle is pressed
2292 /// 3 = right is pressed
2293 /// in sample mode:
2294 /// 11 = left is released
2295 /// 12 = middle is released
2296 /// 13 = right is released
2297 /// -1 = nothing is pressed or released
2298 /// -2 = leave the window
2299 /// else = keycode (keyboard is pressed)
2300 
2301 Int_t TGWin32::RequestLocator(Int_t mode, Int_t ctyp, Int_t & x, Int_t & y)
2302 {
2303  static int xloc = 0;
2304  static int yloc = 0;
2305  static int xlocp = 0;
2306  static int ylocp = 0;
2307  static GdkCursor *cursor = NULL;
2308  Int_t xtmp, ytmp;
2309 
2310  GdkEvent *event;
2311  int button_press;
2312  int radius;
2313 
2314  // Change the cursor shape
2315  if (cursor == NULL) {
2316  if (ctyp > 1) {
2317  gdk_window_set_cursor((GdkWindow *)gCws->window, (GdkCursor *)gNullCursor);
2318  gdk_gc_set_foreground((GdkGC *) gGCecho, &GetColor(0).color);
2319  } else {
2320  if (fUseSysPointers)
2321  cursor = gdk_syscursor_new((ULong_t)IDC_CROSS);
2322  else
2323  cursor = gdk_cursor_new((GdkCursorType)GDK_CROSSHAIR);
2324  gdk_window_set_cursor((GdkWindow *)gCws->window, (GdkCursor *)cursor);
2325  }
2326  }
2327 
2328  // Event loop
2329  button_press = 0;
2330 
2331  // Set max response time to 2 minutes to avoid timeout
2332  // in TGWin32ProxyBase::ForwardCallBack during RequestLocator
2333  TGWin32VirtualXProxy::fMaxResponseTime = 120000;
2334  while (button_press == 0) {
2335  event = gdk_event_get();
2336 
2337  switch (ctyp) {
2338 
2339  case 1:
2340  break;
2341 
2342  case 2:
2343  gdk_draw_line(gCws->window, gGCecho, xloc, 0, xloc, gCws->height);
2344  gdk_draw_line(gCws->window, gGCecho, 0, yloc, gCws->width, yloc);
2345  break;
2346 
2347  case 3:
2348  radius = (int) TMath::Sqrt((double)((xloc - xlocp) * (xloc - xlocp) +
2349  (yloc - ylocp) * (yloc - ylocp)));
2350 
2351  gdk_win32_draw_arc(gCws->window, gGCecho, kFALSE,
2352  xlocp - radius, ylocp - radius,
2353  2 * radius, 2 * radius, 0, 23040);
2354  break;
2355 
2356  case 4:
2357  gdk_draw_line(gCws->window, gGCecho, xlocp, ylocp, xloc, yloc);
2358  break;
2359 
2360  case 5:
2361  gdk_win32_draw_rectangle( gCws->window, gGCecho, kFALSE,
2362  TMath::Min(xlocp, xloc), TMath::Min(ylocp, yloc),
2363  TMath::Abs(xloc - xlocp), TMath::Abs(yloc - ylocp));
2364  break;
2365 
2366  default:
2367  break;
2368  }
2369 
2370  xloc = event->button.x;
2371  yloc = event->button.y;
2372 
2373  switch (event->type) {
2374 
2375  case GDK_LEAVE_NOTIFY:
2376  if (mode == 0) {
2377  while (1) {
2378  event = gdk_event_get();
2379 
2380  if (event->type == GDK_ENTER_NOTIFY) {
2381  gdk_event_free(event);
2382  break;
2383  }
2384  gdk_event_free(event);
2385  }
2386  } else {
2387  button_press = -2;
2388  }
2389  break;
2390 
2391  case GDK_BUTTON_PRESS:
2392  button_press = event->button.button;
2393  xlocp = event->button.x;
2394  ylocp = event->button.y;
2395  gdk_cursor_unref(cursor);
2396  cursor = 0;
2397  break;
2398 
2399  case GDK_BUTTON_RELEASE:
2400  if (mode == 1) {
2401  button_press = 10 + event->button.button;
2402  xlocp = event->button.x;
2403  ylocp = event->button.y;
2404  }
2405  break;
2406 
2407  case GDK_KEY_PRESS:
2408  if (mode == 1) {
2409  button_press = event->key.keyval;
2410  xlocp = event->button.x;
2411  ylocp = event->button.y;
2412  }
2413  break;
2414 
2415  case GDK_KEY_RELEASE:
2416  if (mode == 1) {
2417  button_press = -1 * (int)(event->key.keyval);
2418  xlocp = event->button.x;
2419  ylocp = event->button.y;
2420  }
2421  break;
2422 
2423  default:
2424  break;
2425  }
2426 
2427  xtmp = event->button.x;
2428  ytmp = event->button.y;
2429 
2430  gdk_event_free(event);
2431 
2432  if (mode == 1) {
2433  if (button_press == 0) {
2434  button_press = -1;
2435  }
2436  break;
2437  }
2438  }
2439  TGWin32VirtualXProxy::fMaxResponseTime = 1000;
2440 
2441  x = xtmp;
2442  y = ytmp;
2443 
2444  return button_press;
2445 }
2446 
2447 ////////////////////////////////////////////////////////////////////////////////
2448 /// Request a string.
2449 /// x,y : position where text is displayed
2450 /// text : text displayed (input), edited text (output)
2451 ///
2452 /// Request string:
2453 /// text is displayed and can be edited with Emacs-like keybinding
2454 /// return termination code (0 for ESC, 1 for RETURN)
2455 
2456 Int_t TGWin32::RequestString(int x, int y, char *text)
2457 {
2458  static GdkCursor *cursor = NULL;
2459  static int percent = 0; // bell volume
2460  static GdkWindow *CurWnd;
2461  HWND focuswindow;
2462  GdkEvent *event;
2463  KeySym keysym;
2464  int key = -1;
2465  int len_text = strlen(text);
2466  int nt; // defined length of text
2467  int pt; // cursor position in text
2468 
2469  CurWnd = (GdkWindow *)gCws->window;
2470  // change the cursor shape
2471  if (cursor == NULL) {
2472  if (fUseSysPointers)
2473  cursor = gdk_syscursor_new((ULong_t)IDC_HELP);
2474  else
2475  cursor = gdk_cursor_new((GdkCursorType)GDK_QUESTION_ARROW);
2476  }
2477  if (cursor != 0) {
2478  gdk_window_set_cursor(CurWnd, cursor);
2479  }
2480  for (nt = len_text; nt > 0 && text[nt - 1] == ' '; nt--);
2481 
2482  pt = nt;
2483  focuswindow = ::SetFocus((HWND)GDK_DRAWABLE_XID(CurWnd));
2484 
2485  // Set max response time to 2 minutes to avoid timeout
2486  // in TGWin32ProxyBase::ForwardCallBack during RequestString
2487  TGWin32VirtualXProxy::fMaxResponseTime = 120000;
2488  TTF::SetTextFont(gTextFont);
2489  TTF::SetTextSize(fTextSize);
2490  do {
2491  char tmp[2];
2492  char keybuf[8];
2493  char nbytes;
2494  UInt_t dx, ddx, h;
2495  int i;
2496 
2497  if (EventsPending()) {
2498  event = gdk_event_get();
2499  } else {
2500  gSystem->ProcessEvents();
2501  ::SleepEx(10, kTRUE);
2502  continue;
2503  }
2504 
2505  DrawText(x, y, 0.0, 1.0, text, kOpaque);
2506  TTF::GetTextExtent(dx, h, text);
2507  DrawText(x+dx, y, 0.0, 1.0, " ", kOpaque);
2508 
2509  if (pt == 0) {
2510  dx = 0;
2511  } else {
2512  char *stmp = new char[pt+1];
2513  strncpy(stmp, text, pt);
2514  stmp[pt] = '\0';
2515  TTF::GetTextExtent(ddx, h, stmp);
2516  dx = ddx;
2517  delete[] stmp;
2518  }
2519 
2520  if (pt < len_text) {
2521  tmp[0] = text[pt];
2522  tmp[1] = '\0';
2523  DrawText(x+dx, y, 0.0, 1.0, tmp, kOpaque);
2524  } else {
2525  DrawText(x+dx, y, 0.0, 1.0, " ", kOpaque);
2526  }
2527 
2528  if (event != NULL) {
2529  switch (event->type) {
2530  case GDK_BUTTON_PRESS:
2531  case GDK_ENTER_NOTIFY:
2532  focuswindow = ::SetFocus((HWND)GDK_DRAWABLE_XID(CurWnd));
2533  break;
2534 
2535  case GDK_LEAVE_NOTIFY:
2536  ::SetFocus(focuswindow);
2537  break;
2538  case GDK_KEY_PRESS:
2539  nbytes = event->key.length;
2540  for (i = 0; i < nbytes; i++) {
2541  keybuf[i] = event->key.string[i];
2542  }
2543  keysym = event->key.keyval;
2544  switch (keysym) { // map cursor keys
2545  case GDK_BackSpace:
2546  keybuf[0] = 0x08; // backspace
2547  nbytes = 1;
2548  break;
2549  case GDK_Return:
2550  keybuf[0] = 0x0d; // return
2551  nbytes = 1;
2552  break;
2553  case GDK_Delete:
2554  keybuf[0] = 0x7f; // del
2555  nbytes = 1;
2556  break;
2557  case GDK_Escape:
2558  keybuf[0] = 0x1b; // esc
2559  nbytes = 1;
2560  break;
2561  case GDK_Home:
2562  keybuf[0] = 0x01; // home
2563  nbytes = 1;
2564  break;
2565  case GDK_Left:
2566  keybuf[0] = 0x02; // backward
2567  nbytes = 1;
2568  break;
2569  case GDK_Right:
2570  keybuf[0] = 0x06; // forward
2571  nbytes = 1;
2572  break;
2573  case GDK_End:
2574  keybuf[0] = 0x05; // end
2575  nbytes = 1;
2576  break;
2577  }
2578  if (nbytes == 1) {
2579  if (isascii(keybuf[0]) && isprint(keybuf[0])) {
2580  // insert character
2581  if (nt < len_text) {
2582  nt++;
2583  }
2584  for (i = nt - 1; i > pt; i--) {
2585  text[i] = text[i - 1];
2586  }
2587  if (pt < len_text) {
2588  text[pt] = keybuf[0];
2589  pt++;
2590  }
2591  } else {
2592  switch (keybuf[0]) {
2593  // Emacs-like editing keys
2594 
2595  case 0x08: //'\010': // backspace
2596  case 0x7f: //'\177': // delete
2597  // delete backward
2598  if (pt > 0) {
2599  for (i = pt; i < nt; i++) {
2600  text[i - 1] = text[i];
2601  }
2602  text[nt - 1] = ' ';
2603  nt--;
2604  pt--;
2605  }
2606  break;
2607  case 0x01: //'\001': // ^A
2608  // beginning of line
2609  pt = 0;
2610  break;
2611  case 0x02: //'\002': // ^B
2612  // move backward
2613  if (pt > 0) {
2614  pt--;
2615  }
2616  break;
2617  case 0x04: //'\004': // ^D
2618  // delete forward
2619  if (pt > 0) {
2620  for (i = pt; i < nt; i++) {
2621  text[i - 1] = text[i];
2622  }
2623  text[nt - 1] = ' ';
2624  pt--;
2625  }
2626  break;
2627  case 0x05: //'\005': // ^E
2628  // end of line
2629  pt = nt;
2630  break;
2631 
2632  case 0x06: //'\006': // ^F
2633  // move forward
2634  if (pt < nt) {
2635  pt++;
2636  }
2637  break;
2638  case 0x0b: //'\013': // ^K
2639  // delete to end of line
2640  for (i = pt; i < nt; i++)
2641  text[i] = ' ';
2642  nt = pt;
2643  break;
2644  case 0x14: //'\024': // ^T
2645  // transpose
2646  if (pt > 0) {
2647  char c = text[pt];
2648  text[pt] = text[pt - 1];
2649  text[pt - 1] = c;
2650  }
2651  break;
2652  case 0x0A: //'\012': // newline
2653  case 0x0D: //'\015': // return
2654  key = 1;
2655  break;
2656  case 0x1B: //'\033': // escape
2657  key = 0;
2658  break;
2659 
2660  default:
2661  gSystem->Beep();
2662  break;
2663  }
2664  }
2665  }
2666  default:
2667  SetInputFocus((Window_t)gCws->window);
2668  break;
2669  }
2670  gdk_event_free(event);
2671  }
2672  } while (key < 0);
2673  TGWin32VirtualXProxy::fMaxResponseTime = 1000;
2674  ::SetFocus(focuswindow);
2675  SetInputFocus((Window_t)CurWnd);
2676 
2677  gdk_window_set_cursor(CurWnd, (GdkCursor *)fCursors[kPointer]);
2678  if (cursor != 0) {
2679  gdk_cursor_unref(cursor);
2680  cursor = 0;
2681  }
2682 
2683  return key;
2684 }
2685 
2686 ////////////////////////////////////////////////////////////////////////////////
2687 /// Rescale the window wid.
2688 /// wid : GdkWindow identifier
2689 /// w : Width
2690 /// h : Heigth
2691 
2692 void TGWin32::RescaleWindow(int wid, unsigned int w, unsigned int h)
2693 {
2694  int i;
2695 
2696  if (!fWindows) return;
2697 
2698  gTws = &fWindows[wid];
2699  if (!gTws->open)
2700  return;
2701 
2702  // don't do anything when size did not change
2703  if (gTws->width == w && gTws->height == h)
2704  return;
2705 
2706  gdk_window_resize((GdkWindow *) gTws->window, w, h);
2707 
2708  if (gTws->buffer) {
2709  // don't free and recreate pixmap when new pixmap is smaller
2710  if (gTws->width < w || gTws->height < h) {
2711  gdk_pixmap_unref(gTws->buffer);
2712  gTws->buffer = gdk_pixmap_new(GDK_ROOT_PARENT(), // NULL,
2713  w, h, gdk_visual_get_best_depth());
2714  }
2715  for (i = 0; i < kMAXGC; i++) {
2716  gdk_gc_set_clip_mask(gGClist[i], None);
2717  }
2718  SetColor(gGCpxmp, 0);
2719  gdk_win32_draw_rectangle(gTws->buffer, gGCpxmp, 1, 0, 0, w, h);
2720  SetColor(gGCpxmp, 1);
2721 
2722  if (gTws->double_buffer) gTws->drawing = gTws->buffer;
2723  }
2724  gTws->width = w;
2725  gTws->height = h;
2726 }
2727 
2728 ////////////////////////////////////////////////////////////////////////////////
2729 /// Resize a pixmap.
2730 /// wid : pixmap to be resized
2731 /// w,h : Width and height of the pixmap
2732 
2733 int TGWin32::ResizePixmap(int wid, unsigned int w, unsigned int h)
2734 {
2735  int wval, hval;
2736  int i;
2737  int ww, hh, depth;
2738  wval = w;
2739  hval = h;
2740 
2741  if (!fWindows) return 0;
2742 
2743  gTws = &fWindows[wid];
2744 
2745  // don't do anything when size did not change
2746  // if (gTws->width == wval && gTws->height == hval) return 0;
2747 
2748  // due to round-off errors in TPad::Resize() we might get +/- 1 pixel
2749  // change, in those cases don't resize pixmap
2750  if (gTws->width >= wval - 1 && gTws->width <= wval + 1 &&
2751  gTws->height >= hval - 1 && gTws->height <= hval + 1)
2752  return 0;
2753 
2754  // don't free and recreate pixmap when new pixmap is smaller
2755  if (gTws->width < wval || gTws->height < hval) {
2756  gdk_pixmap_unref((GdkPixmap *)gTws->window);
2757  depth = gdk_visual_get_best_depth();
2758  gTws->window = gdk_pixmap_new(GDK_ROOT_PARENT(), wval, hval, depth);
2759  }
2760 
2761  gdk_drawable_get_size(gTws->window, &ww, &hh);
2762 
2763  for (i = 0; i < kMAXGC; i++) {
2764  gdk_gc_set_clip_mask((GdkGC *) gGClist[i], (GdkDrawable *)None);
2765  }
2766 
2767  SetColor(gGCpxmp, 0);
2768  gdk_win32_draw_rectangle(gTws->window,(GdkGC *)gGCpxmp, kTRUE, 0, 0, ww, hh);
2769  SetColor(gGCpxmp, 1);
2770 
2771  // Initialise the window structure
2772  gTws->drawing = gTws->window;
2773  gTws->width = wval;
2774  gTws->height = hval;
2775  return 1;
2776 }
2777 
2778 ////////////////////////////////////////////////////////////////////////////////
2779 /// Resize the current window if necessary.
2780 
2781 void TGWin32::ResizeWindow(int wid)
2782 {
2783  int i;
2784  int xval = 0, yval = 0;
2785  GdkWindow *win, *root = NULL;
2786  int wval = 0, hval = 0, depth = 0;
2787 
2788  if (!fWindows) return;
2789 
2790  gTws = &fWindows[wid];
2791 
2792  win = (GdkWindow *) gTws->window;
2793  gdk_window_get_geometry(win, &xval, &yval,
2794  &wval, &hval, &depth);
2795 
2796  // don't do anything when size did not change
2797  if (gTws->width == wval && gTws->height == hval) {
2798  return;
2799  }
2800 
2801  gdk_window_resize((GdkWindow *) gTws->window, wval, hval);
2802 
2803  if (gTws->buffer) {
2804  if (gTws->width < wval || gTws->height < hval) {
2805  gdk_pixmap_unref((GdkPixmap *)gTws->buffer);
2806  depth = gdk_visual_get_best_depth();
2807  gTws->buffer = (GdkPixmap *) gdk_pixmap_new(GDK_ROOT_PARENT(),
2808  wval, hval, depth);
2809  }
2810 
2811  for (i = 0; i < kMAXGC; i++) {
2812  gdk_gc_set_clip_mask((GdkGC *) gGClist[i], (GdkDrawable *)None);
2813  }
2814 
2815  SetColor(gGCpxmp, 0);
2816  gdk_win32_draw_rectangle(gTws->buffer,(GdkGC *)gGCpxmp, kTRUE, 0, 0, wval, hval);
2817 
2818  SetColor(gGCpxmp, 1);
2819 
2820  if (gTws->double_buffer) gTws->drawing = gTws->buffer;
2821  }
2822 
2823  gTws->width = wval;
2824  gTws->height = hval;
2825 }
2826 
2827 ////////////////////////////////////////////////////////////////////////////////
2828 /// Select window to which subsequent output is directed.
2829 
2830 void TGWin32::SelectWindow(int wid)
2831 {
2832  int i;
2833  GdkRectangle rect;
2834 
2835  if (!fWindows || wid < 0 || wid >= fMaxNumberOfWindows || !fWindows[wid].open) {
2836  return;
2837  }
2838 
2839  gCws = &fWindows[wid];
2840 
2841  if (gCws->clip && !gCws->ispixmap && !gCws->double_buffer) {
2842  rect.x = gCws->xclip;
2843  rect.y = gCws->yclip;
2844  rect.width = gCws->wclip;
2845  rect.height = gCws->hclip;
2846 
2847  for (i = 0; i < kMAXGC; i++) {
2848  gdk_gc_set_clip_rectangle((GdkGC *) gGClist[i], &rect);
2849  }
2850  } else {
2851  for (i = 0; i < kMAXGC; i++) {
2852  gdk_gc_set_clip_mask((GdkGC *) gGClist[i], (GdkDrawable *)None);
2853  }
2854  }
2855 }
2856 
2857 ////////////////////////////////////////////////////////////////////////////////
2858 /// Set character up vector.
2859 
2860 void TGWin32::SetCharacterUp(Float_t chupx, Float_t chupy)
2861 {
2862  if (chupx == fCharacterUpX && chupy == fCharacterUpY) return;
2863 
2864  if (chupx == 0 && chupy == 0) {
2865  fTextAngle = 0;
2866  } else if (chupx == 0 && chupy == 1) {
2867  fTextAngle = 0;
2868  } else if (chupx == -1 && chupy == 0) {
2869  fTextAngle = 90;
2870  } else if (chupx == 0 && chupy == -1) {
2871  fTextAngle = 180;
2872  } else if (chupx == 1 && chupy == 0) {
2873  fTextAngle = 270;
2874  } else {
2875  fTextAngle =
2876  ((TMath::
2877  ACos(chupx / TMath::Sqrt(chupx * chupx + chupy * chupy)) *
2878  180.) / 3.14159) - 90;
2879  if (chupy < 0) fTextAngle = 180 - fTextAngle;
2880  if (TMath::Abs(fTextAngle) <= 0.01) fTextAngle = 0;
2881  }
2882  fCharacterUpX = chupx;
2883  fCharacterUpY = chupy;
2884 }
2885 
2886 ////////////////////////////////////////////////////////////////////////////////
2887 /// Turn off the clipping for the window wid.
2888 
2889 void TGWin32::SetClipOFF(int wid)
2890 {
2891  if (!fWindows) return;
2892 
2893  gTws = &fWindows[wid];
2894  gTws->clip = 0;
2895 
2896  for (int i = 0; i < kMAXGC; i++) {
2897  gdk_gc_set_clip_mask((GdkGC *) gGClist[i], (GdkDrawable *)None);
2898  }
2899 }
2900 
2901 ////////////////////////////////////////////////////////////////////////////////
2902 /// Set clipping region for the window wid.
2903 /// wid : GdkWindow indentifier
2904 /// x,y : origin of clipping rectangle
2905 /// w,h : size of clipping rectangle;
2906 
2907 void TGWin32::SetClipRegion(int wid, int x, int y, unsigned int w,
2908  unsigned int h)
2909 {
2910  if (!fWindows) return;
2911 
2912  gTws = &fWindows[wid];
2913  gTws->xclip = x;
2914  gTws->yclip = y;
2915  gTws->wclip = w;
2916  gTws->hclip = h;
2917  gTws->clip = 1;
2918  GdkRectangle rect;
2919 
2920  if (gTws->clip && !gTws->ispixmap && !gTws->double_buffer) {
2921  rect.x = gTws->xclip;
2922  rect.y = gTws->yclip;
2923  rect.width = gTws->wclip;
2924  rect.height = gTws->hclip;
2925 
2926  for (int i = 0; i < kMAXGC; i++) {
2927  gdk_gc_set_clip_rectangle((GdkGC *)gGClist[i], &rect);
2928  }
2929  }
2930 }
2931 
2932 ////////////////////////////////////////////////////////////////////////////////
2933 /// Return pixel value associated to specified ROOT color number.
2934 
2935 ULong_t TGWin32::GetPixel(Color_t ci)
2936 {
2937  TColor *color = gROOT->GetColor(ci);
2938  if (color)
2939  SetRGB(ci, color->GetRed(), color->GetGreen(), color->GetBlue());
2940  XColor_t &col = GetColor(ci);
2941  return col.color.pixel;
2942 }
2943 
2944 ////////////////////////////////////////////////////////////////////////////////
2945 /// Set the foreground color in GdkGC.
2946 
2947 void TGWin32::SetColor(GdkGC *gc, int ci)
2948 {
2949  GdkGCValues gcvals;
2950  GdkColor color;
2951 
2952  if (ci<=0) ci = 10; //white
2953 
2954  TColor *clr = gROOT->GetColor(ci);
2955  if (clr)
2956  SetRGB(ci, clr->GetRed(), clr->GetGreen(), clr->GetBlue());
2957 
2958  XColor_t &col = GetColor(ci);
2959  if (fColormap && !col.fDefined) {
2960  col = GetColor(0);
2961  } else if (!fColormap && (ci < 0 || ci > 1)) {
2962  col = GetColor(0);
2963  }
2964 
2965  if (fDrawMode == kXor) {
2966  gdk_gc_get_values(gc, &gcvals);
2967 
2968  color.pixel = col.color.pixel ^ gcvals.background.pixel;
2969  color.red = GetRValue(color.pixel);
2970  color.green = GetGValue(color.pixel);
2971  color.blue = GetBValue(color.pixel);
2972  gdk_gc_set_foreground(gc, &color);
2973 
2974  } else {
2975  gdk_gc_set_foreground(gc, &col.color);
2976 
2977  // make sure that foreground and background are different
2978  gdk_gc_get_values(gc, &gcvals);
2979 
2980  if (gcvals.foreground.pixel != gcvals.background.pixel) {
2981  gdk_gc_set_background(gc, &GetColor(!ci).color);
2982  }
2983  }
2984 }
2985 
2986 ////////////////////////////////////////////////////////////////////////////////
2987 /// Set the cursor.
2988 
2989 void TGWin32::SetCursor(int wid, ECursor cursor)
2990 {
2991  if (!fWindows) return;
2992 
2993  gTws = &fWindows[wid];
2994  gdk_window_set_cursor((GdkWindow *)gTws->window, (GdkCursor *)fCursors[cursor]);
2995 }
2996 
2997 ////////////////////////////////////////////////////////////////////////////////
2998 /// Set the specified cursor.
2999 
3000 void TGWin32::SetCursor(Window_t id, Cursor_t curid)
3001 {
3002  if (!id) return;
3003 
3004  static GdkWindow *lid = 0;
3005  static GdkCursor *lcur = 0;
3006 
3007  if ((lid == (GdkWindow *)id) && (lcur==(GdkCursor *)curid)) return;
3008  lid = (GdkWindow *)id;
3009  lcur = (GdkCursor *)curid;
3010 
3011  gdk_window_set_cursor((GdkWindow *) id, (GdkCursor *)curid);
3012 }
3013 
3014 ////////////////////////////////////////////////////////////////////////////////
3015 /// Set the double buffer on/off on window wid.
3016 /// wid : GdkWindow identifier.
3017 /// 999 means all the opened windows.
3018 /// mode : 1 double buffer is on
3019 /// 0 double buffer is off
3020 
3021 void TGWin32::SetDoubleBuffer(int wid, int mode)
3022 {
3023  if (!fWindows) return;
3024 
3025  if (wid == 999) {
3026  for (int i = 0; i < fMaxNumberOfWindows; i++) {
3027  gTws = &fWindows[i];
3028  if (gTws->open) {
3029  switch (mode) {
3030  case 1:
3031  SetDoubleBufferON();
3032  break;
3033  default:
3034  SetDoubleBufferOFF();
3035  break;
3036  }
3037  }
3038  }
3039  } else {
3040  gTws = &fWindows[wid];
3041  if (!gTws->open) return;
3042 
3043  switch (mode) {
3044  case 1:
3045  SetDoubleBufferON();
3046  return;
3047  default:
3048  SetDoubleBufferOFF();
3049  return;
3050  }
3051  }
3052 }
3053 
3054 ////////////////////////////////////////////////////////////////////////////////
3055 /// Turn double buffer mode off.
3056 
3057 void TGWin32::SetDoubleBufferOFF()
3058 {
3059  if (!gTws->double_buffer) return;
3060  gTws->double_buffer = 0;
3061  gTws->drawing = gTws->window;
3062 }
3063 
3064 ////////////////////////////////////////////////////////////////////////////////
3065 /// Turn double buffer mode on.
3066 
3067 void TGWin32::SetDoubleBufferON()
3068 {
3069  if (!fWindows || gTws->double_buffer || gTws->ispixmap) return;
3070 
3071  if (!gTws->buffer) {
3072  gTws->buffer = gdk_pixmap_new(GDK_ROOT_PARENT(), //NULL,
3073  gTws->width, gTws->height,
3074  gdk_visual_get_best_depth());
3075  SetColor(gGCpxmp, 0);
3076  gdk_win32_draw_rectangle(gTws->buffer, gGCpxmp, 1, 0, 0, gTws->width,
3077  gTws->height);
3078  SetColor(gGCpxmp, 1);
3079  }
3080  for (int i = 0; i < kMAXGC; i++) {
3081  gdk_gc_set_clip_mask(gGClist[i], None);
3082  }
3083  gTws->double_buffer = 1;
3084  gTws->drawing = gTws->buffer;
3085 }
3086 
3087 ////////////////////////////////////////////////////////////////////////////////
3088 /// Set the drawing mode.
3089 /// mode : drawing mode
3090 /// mode=1 copy
3091 /// mode=2 xor
3092 /// mode=3 invert
3093 /// mode=4 set the suitable mode for cursor echo according to
3094 /// the vendor
3095 
3096 void TGWin32::SetDrawMode(EDrawMode mode)
3097 {
3098  int i;
3099 
3100  switch (mode) {
3101  case kCopy:
3102  for (i = 0; i < kMAXGC; i++) {
3103  gdk_gc_set_function(gGClist[i], GDK_COPY);
3104  }
3105  break;
3106 
3107  case kXor:
3108  for (i = 0; i < kMAXGC; i++) {
3109  gdk_gc_set_function(gGClist[i], GDK_XOR);
3110  }
3111  break;
3112 
3113  case kInvert:
3114  for (i = 0; i < kMAXGC; i++) {
3115  gdk_gc_set_function(gGClist[i], GDK_INVERT);
3116  }
3117  break;
3118  }
3119  fDrawMode = mode;
3120 }
3121 
3122 ////////////////////////////////////////////////////////////////////////////////
3123 /// Set color index for fill areas.
3124 
3125 void TGWin32::SetFillColor(Color_t cindex)
3126 {
3127  Int_t indx = Int_t(cindex);
3128 
3129  if (!gStyle->GetFillColor() && cindex > 1) {
3130  indx = 0;
3131  }
3132 
3133  fFillColor = indx;
3134  fFillColorModified = kTRUE;
3135 }
3136 
3137 ////////////////////////////////////////////////////////////////////////////////
3138 ///
3139 
3140 void TGWin32::UpdateFillColor()
3141 {
3142  if (fFillColor >= 0) {
3143  SetColor(gGCfill, fFillColor);
3144  }
3145 
3146  // invalidate fill pattern
3147  if (gFillPattern != NULL) {
3148  gdk_pixmap_unref(gFillPattern);
3149  gFillPattern = NULL;
3150  }
3151  fFillColorModified = kFALSE;
3152 }
3153 
3154 ////////////////////////////////////////////////////////////////////////////////
3155 /// Set fill area style.
3156 /// fstyle : compound fill area interior style
3157 /// fstyle = 1000*interiorstyle + styleindex
3158 
3159 void TGWin32::SetFillStyle(Style_t fstyle)
3160 {
3161  if (fFillStyle==fstyle) return;
3162 
3163  fFillStyle = fstyle;
3164  fFillStyleModified = kTRUE;
3165 }
3166 
3167 ////////////////////////////////////////////////////////////////////////////////
3168 /// Set fill area style index.
3169 
3170 void TGWin32::UpdateFillStyle()
3171 {
3172  static int current_fasi = 0;
3173 
3174  Int_t style = fFillStyle / 1000;
3175  Int_t fasi = fFillStyle % 1000;
3176 
3177  switch (style) {
3178 
3179  case 1: // solid
3180  gFillHollow = 0;
3181  gdk_gc_set_fill(gGCfill, GDK_SOLID);
3182  break;
3183 
3184  case 2: // pattern
3185  gFillHollow = 1;
3186  break;
3187 
3188  case 3: // hatch
3189  gFillHollow = 0;
3190  gdk_gc_set_fill(gGCfill, GDK_STIPPLED);
3191 
3192  if (fasi != current_fasi) {
3193  if (gFillPattern != NULL) {
3194  gdk_pixmap_unref(gFillPattern);
3195  gFillPattern = NULL;
3196  }
3197  int stn = (fasi >= 1 && fasi <=25) ? fasi : 2;
3198  gFillPattern = gdk_bitmap_create_from_data(GDK_ROOT_PARENT(),
3199  (const char *)gStipples[stn], 16, 16);
3200  gdk_gc_set_stipple(gGCfill, gFillPattern);
3201  current_fasi = fasi;
3202  }
3203  break;
3204 
3205  default:
3206  gFillHollow = 1;
3207  }
3208 
3209  fFillStyleModified = kFALSE;
3210 }
3211 
3212 ////////////////////////////////////////////////////////////////////////////////
3213 /// Set input on or off.
3214 
3215 void TGWin32::SetInput(int inp)
3216 {
3217  EnableWindow((HWND) GDK_DRAWABLE_XID(gCws->window), inp);
3218 }
3219 
3220 ////////////////////////////////////////////////////////////////////////////////
3221 /// Set color index for lines.
3222 
3223 void TGWin32::SetLineColor(Color_t cindex)
3224 {
3225  if ((cindex < 0) || (cindex==fLineColor)) return;
3226 
3227  fLineColor = cindex;
3228  fLineColorModified = kTRUE;
3229 }
3230 
3231 ////////////////////////////////////////////////////////////////////////////////
3232 ///
3233 
3234 void TGWin32::UpdateLineColor()
3235 {
3236  SetColor(gGCline, Int_t(fLineColor));
3237  SetColor(gGCdash, Int_t(fLineColor));
3238  fLineColorModified = kFALSE;
3239 }
3240 
3241 ////////////////////////////////////////////////////////////////////////////////
3242 /// Set line type.
3243 /// n : length of dash list
3244 /// dash(n) : dash segment lengths
3245 ///
3246 /// if n <= 0 use solid lines
3247 /// if n > 0 use dashed lines described by DASH(N)
3248 /// e.g. N=4,DASH=(6,3,1,3) gives a dashed-dotted line with dash length 6
3249 /// and a gap of 7 between dashes
3250 
3251 void TGWin32::SetLineType(int n, int *dash)
3252 {
3253  if (n <= 0) {
3254  gLineStyle = GDK_LINE_SOLID;
3255  gdk_gc_set_line_attributes(gGCline, gLineWidth,
3256  (GdkLineStyle)gLineStyle,
3257  (GdkCapStyle) gCapStyle,
3258  (GdkJoinStyle) gJoinStyle);
3259  } else {
3260  int i;
3261  gDashSize = TMath::Min((int)sizeof(gDashList),n);
3262  gDashLength = 0;
3263  for (i = 0; i < gDashSize; i++) {
3264  gDashList[i] = dash[i];
3265  gDashLength += gDashList[i];
3266  }
3267  gDashOffset = 0;
3268  gLineStyle = GDK_LINE_ON_OFF_DASH;
3269  if (gLineWidth == 0) gLineWidth =1;
3270  gdk_gc_set_line_attributes(gGCdash, gLineWidth,
3271  (GdkLineStyle) gLineStyle,
3272  (GdkCapStyle) gCapStyle,
3273  (GdkJoinStyle) gJoinStyle);
3274  }
3275  fPenModified = kFALSE;
3276 }
3277 
3278 ////////////////////////////////////////////////////////////////////////////////
3279 /// Set line style.
3280 
3281 void TGWin32::SetLineStyle(Style_t lstyle)
3282 {
3283  if (fLineStyle == lstyle) return;
3284 
3285  fLineStyle = lstyle;
3286  fPenModified = kTRUE;
3287 }
3288 
3289 ////////////////////////////////////////////////////////////////////////////////
3290 /// Update line style
3291 
3292 void TGWin32::UpdateLineStyle()
3293 {
3294  static Int_t dashed[2] = { 3, 3 };
3295  static Int_t dotted[2] = { 1, 2 };
3296  static Int_t dasheddotted[4] = { 3, 4, 1, 4 };
3297 
3298  if (fLineStyle <= 1) {
3299  SetLineType(0, 0);
3300  } else if (fLineStyle == 2) {
3301  SetLineType(2, dashed);
3302  } else if (fLineStyle == 3) {
3303  SetLineType(2, dotted);
3304  } else if (fLineStyle == 4) {
3305  SetLineType(4, dasheddotted);
3306  } else {
3307  TString st = (TString)gStyle->GetLineStyleString(fLineStyle);
3308  TObjArray *tokens = st.Tokenize(" ");
3309  Int_t nt;
3310  nt = tokens->GetEntries();
3311  Int_t *linestyle = new Int_t[nt];
3312  for (Int_t j = 0; j<nt; j++) {
3313  Int_t it;
3314  sscanf(((TObjString*)tokens->At(j))->GetName(), "%d", &it);
3315  linestyle[j] = (Int_t)(it/4);
3316  }
3317  SetLineType(nt,linestyle);
3318  delete [] linestyle;
3319  delete tokens;
3320  }
3321  fPenModified = kFALSE;
3322 }
3323 
3324 ////////////////////////////////////////////////////////////////////////////////
3325 /// Set line width.
3326 /// width : line width in pixels
3327 
3328 void TGWin32::SetLineWidth(Width_t width)
3329 {
3330  if (fLineWidth == width) return;
3331  fLineWidth = width;
3332 
3333  if (width == 1 && gLineStyle == GDK_LINE_SOLID) gLineWidth = 0;
3334  else gLineWidth = width;
3335 
3336  fPenModified = kTRUE;
3337 }
3338 
3339 ////////////////////////////////////////////////////////////////////////////////
3340 /// Set color index for markers.
3341 
3342 void TGWin32::SetMarkerColor(Color_t cindex)
3343 {
3344  if ((cindex<0) || (cindex==fMarkerColor)) return;
3345  fMarkerColor = cindex;
3346  fMarkerColorModified = kTRUE;
3347 }
3348 
3349 ////////////////////////////////////////////////////////////////////////////////
3350 ///
3351 
3352 void TGWin32::UpdateMarkerColor()
3353 {
3354  SetColor(gGCmark, Int_t(fMarkerColor));
3355  fMarkerColorModified = kFALSE;
3356 }
3357 
3358 ////////////////////////////////////////////////////////////////////////////////
3359 /// Set marker size index.
3360 /// msize : marker scale factor
3361 
3362 void TGWin32::SetMarkerSize(Float_t msize)
3363 {
3364  if ((msize==fMarkerSize) || (msize<0)) return;
3365 
3366  fMarkerSize = msize;
3367  SetMarkerStyle(-fMarkerStyle);
3368 }
3369 
3370 ////////////////////////////////////////////////////////////////////////////////
3371 /// Set marker type.
3372 /// type : marker type
3373 /// n : length of marker description
3374 /// xy : list of points describing marker shape
3375 ///
3376 /// if n == 0 marker is a single point
3377 /// if TYPE == 0 marker is hollow circle of diameter N
3378 /// if TYPE == 1 marker is filled circle of diameter N
3379 /// if TYPE == 2 marker is a hollow polygon describe by line XY
3380 /// if TYPE == 3 marker is a filled polygon describe by line XY
3381 /// if TYPE == 4 marker is described by segmented line XY
3382 /// e.g. TYPE=4,N=4,XY=(-3,0,3,0,0,-3,0,3) sets a plus shape of 7x7 pixels
3383 
3384 void TGWin32::SetMarkerType(int type, int n, GdkPoint * xy)
3385 {
3386  gMarker.type = type;
3387  gMarker.n = n < kMAXMK ? n : kMAXMK;
3388  if (gMarker.type >= 2) {
3389  for (int i = 0; i < gMarker.n; i++) {
3390  gMarker.xy[i] = xy[i];
3391  }
3392  }
3393 }
3394 
3395 ////////////////////////////////////////////////////////////////////////////////
3396 /// Set marker style.
3397 
3398 void TGWin32::SetMarkerStyle(Style_t markerstyle)
3399 {
3400  if ((fMarkerStyle == markerstyle) || (markerstyle >= 50)) return;
3401  fMarkerStyle = TMath::Abs(markerstyle);
3402  fMarkerStyleModified = kTRUE;
3403 }
3404 
3405 ////////////////////////////////////////////////////////////////////////////////
3406 ///
3407 
3408 void TGWin32::UpdateMarkerStyle()
3409 {
3410  static GdkPoint shape[30];
3411 
3412  Int_t im = Int_t(4 * fMarkerSize + 0.5);
3413 
3414  if (fMarkerStyle == 2) {
3415  // + shaped marker
3416  shape[0].x = -im;
3417  shape[0].y = 0;
3418  shape[1].x = im;
3419  shape[1].y = 0;
3420  shape[2].x = 0;
3421  shape[2].y = -im;
3422  shape[3].x = 0;
3423  shape[3].y = im;
3424  SetMarkerType(4, 4, shape);
3425  } else if (fMarkerStyle == 3 || fMarkerStyle == 31) {
3426  // * shaped marker
3427  shape[0].x = -im;
3428  shape[0].y = 0;
3429  shape[1].x = im;
3430  shape[1].y = 0;
3431  shape[2].x = 0;
3432  shape[2].y = -im;
3433  shape[3].x = 0;
3434  shape[3].y = im;
3435  im = Int_t(0.707 * Float_t(im) + 0.5);
3436  shape[4].x = -im;
3437  shape[4].y = -im;
3438  shape[5].x = im;
3439  shape[5].y = im;
3440  shape[6].x = -im;
3441  shape[6].y = im;
3442  shape[7].x = im;
3443  shape[7].y = -im;
3444  SetMarkerType(4, 8, shape);
3445  } else if (fMarkerStyle == 4 || fMarkerStyle == 24) {
3446  // O shaped marker
3447  SetMarkerType(0, im * 2, shape);
3448  } else if (fMarkerStyle == 5) {
3449  // X shaped marker
3450  im = Int_t(0.707 * Float_t(im) + 0.5);
3451  shape[0].x = -im;
3452  shape[0].y = -im;
3453  shape[1].x = im;
3454  shape[1].y = im;
3455  shape[2].x = -im;
3456  shape[2].y = im;
3457  shape[3].x = im;
3458  shape[3].y = -im;
3459  SetMarkerType(4, 4, shape);
3460  } else if (fMarkerStyle == 6) {
3461  // + shaped marker (with 1 pixel)
3462  shape[0].x = -1;
3463  shape[0].y = 0;
3464  shape[1].x = 1;
3465  shape[1].y = 0;
3466  shape[2].x = 0;
3467  shape[2].y = -1;
3468  shape[3].x = 0;
3469  shape[3].y = 1;
3470  SetMarkerType(4, 4, shape);
3471  } else if (fMarkerStyle == 7) {
3472  // . shaped marker (with 9 pixel)
3473  shape[0].x = -1;
3474  shape[0].y = 1;
3475  shape[1].x = 1;
3476  shape[1].y = 1;
3477  shape[2].x = -1;
3478  shape[2].y = 0;
3479  shape[3].x = 1;
3480  shape[3].y = 0;
3481  shape[4].x = -1;
3482  shape[4].y = -1;
3483  shape[5].x = 1;
3484  shape[5].y = -1;
3485  SetMarkerType(4, 6, shape);
3486  } else if (fMarkerStyle == 8 || fMarkerStyle == 20) {
3487  // O shaped marker (filled)
3488  SetMarkerType(1, im * 2, shape);
3489  } else if (fMarkerStyle == 21) {
3490  // full square
3491  shape[0].x = -im;
3492  shape[0].y = -im;
3493  shape[1].x = im;
3494  shape[1].y = -im;
3495  shape[2].x = im;
3496  shape[2].y = im;
3497  shape[3].x = -im;
3498  shape[3].y = im;
3499  shape[4].x = -im;
3500  shape[4].y = -im;
3501  SetMarkerType(3, 5, shape);
3502  } else if (fMarkerStyle == 22) {
3503  // full triangle up
3504  shape[0].x = -im;
3505  shape[0].y = im;
3506  shape[1].x = im;
3507  shape[1].y = im;
3508  shape[2].x = 0;
3509  shape[2].y = -im;
3510  shape[3].x = -im;
3511  shape[3].y = im;
3512  SetMarkerType(3, 4, shape);
3513  } else if (fMarkerStyle == 23) {
3514  // full triangle down
3515  shape[0].x = 0;
3516  shape[0].y = im;
3517  shape[1].x = im;
3518  shape[1].y = -im;
3519  shape[2].x = -im;
3520  shape[2].y = -im;
3521  shape[3].x = 0;
3522  shape[3].y = im;
3523  SetMarkerType(3, 4, shape);
3524  } else if (fMarkerStyle == 25) {
3525  // open square
3526  shape[0].x = -im;
3527  shape[0].y = -im;
3528  shape[1].x = im;
3529  shape[1].y = -im;
3530  shape[2].x = im;
3531  shape[2].y = im;
3532  shape[3].x = -im;
3533  shape[3].y = im;
3534  shape[4].x = -im;
3535  shape[4].y = -im;
3536  SetMarkerType(2, 5, shape);
3537  } else if (fMarkerStyle == 26) {
3538  // open triangle up
3539  shape[0].x = -im;
3540  shape[0].y = im;
3541  shape[1].x = im;
3542  shape[1].y = im;
3543  shape[2].x = 0;
3544  shape[2].y = -im;
3545  shape[3].x = -im;
3546  shape[3].y = im;
3547  SetMarkerType(2, 4, shape);
3548  } else if (fMarkerStyle == 27) {
3549  // open losange
3550  Int_t imx = Int_t(2.66 * fMarkerSize + 0.5);
3551  shape[0].x = -imx;
3552  shape[0].y = 0;
3553  shape[1].x = 0;
3554  shape[1].y = -im;
3555  shape[2].x = imx;
3556  shape[2].y = 0;
3557  shape[3].x = 0;
3558  shape[3].y = im;
3559  shape[4].x = -imx;
3560  shape[4].y = 0;
3561  SetMarkerType(2, 5, shape);
3562  } else if (fMarkerStyle == 28) {
3563  // open cross
3564  Int_t imx = Int_t(1.33 * fMarkerSize + 0.5);
3565  shape[0].x = -im;
3566  shape[0].y = -imx;
3567  shape[1].x = -imx;
3568  shape[1].y = -imx;
3569  shape[2].x = -imx;
3570  shape[2].y = -im;
3571  shape[3].x = imx;
3572  shape[3].y = -im;
3573  shape[4].x = imx;
3574  shape[4].y = -imx;
3575  shape[5].x = im;
3576  shape[5].y = -imx;
3577  shape[6].x = im;
3578  shape[6].y = imx;
3579  shape[7].x = imx;
3580  shape[7].y = imx;
3581  shape[8].x = imx;
3582  shape[8].y = im;
3583  shape[9].x = -imx;
3584  shape[9].y = im;
3585  shape[10].x = -imx;
3586  shape[10].y = imx;
3587  shape[11].x = -im;
3588  shape[11].y = imx;
3589  shape[12].x = -im;
3590  shape[12].y = -imx;
3591  SetMarkerType(2, 13, shape);
3592  } else if (fMarkerStyle == 29) {
3593  // full star pentagone
3594  Int_t im1 = Int_t(0.66 * fMarkerSize + 0.5);
3595  Int_t im2 = Int_t(2.00 * fMarkerSize + 0.5);
3596  Int_t im3 = Int_t(2.66 * fMarkerSize + 0.5);
3597  Int_t im4 = Int_t(1.33 * fMarkerSize + 0.5);
3598  shape[0].x = -im;
3599  shape[0].y = im4;
3600  shape[1].x = -im2;
3601  shape[1].y = -im1;
3602  shape[2].x = -im3;
3603  shape[2].y = -im;
3604  shape[3].x = 0;
3605  shape[3].y = -im2;
3606  shape[4].x = im3;
3607  shape[4].y = -im;
3608  shape[5].x = im2;
3609  shape[5].y = -im1;
3610  shape[6].x = im;
3611  shape[6].y = im4;
3612  shape[7].x = im4;
3613  shape[7].y = im4;
3614  shape[8].x = 0;
3615  shape[8].y = im;
3616  shape[9].x = -im4;
3617  shape[9].y = im4;
3618  shape[10].x = -im;
3619  shape[10].y = im4;
3620  SetMarkerType(3, 11, shape);
3621  } else if (fMarkerStyle == 30) {
3622  // open star pentagone
3623  Int_t im1 = Int_t(0.66 * fMarkerSize + 0.5);
3624  Int_t im2 = Int_t(2.00 * fMarkerSize + 0.5);
3625  Int_t im3 = Int_t(2.66 * fMarkerSize + 0.5);
3626  Int_t im4 = Int_t(1.33 * fMarkerSize + 0.5);
3627  shape[0].x = -im;
3628  shape[0].y = im4;
3629  shape[1].x = -im2;
3630  shape[1].y = -im1;
3631  shape[2].x = -im3;
3632  shape[2].y = -im;
3633  shape[3].x = 0;
3634  shape[3].y = -im2;
3635  shape[4].x = im3;
3636  shape[4].y = -im;
3637  shape[5].x = im2;
3638  shape[5].y = -im1;
3639  shape[6].x = im;
3640  shape[6].y = im4;
3641  shape[7].x = im4;
3642  shape[7].y = im4;
3643  shape[8].x = 0;
3644  shape[8].y = im;
3645  shape[9].x = -im4;
3646  shape[9].y = im4;
3647  shape[10].x = -im;
3648  shape[10].y = im4;
3649  SetMarkerType(2, 11, shape);
3650  } else if (fMarkerStyle == 32) {
3651  // open triangle down
3652  shape[0].x = 0; shape[0].y = im;
3653  shape[1].x = im; shape[1].y = -im;
3654  shape[2].x = -im; shape[2].y = -im;
3655  shape[3].x = 0; shape[3].y = im;
3656  SetMarkerType(2,4,shape);
3657  } else if (fMarkerStyle == 33) {
3658  // full losange
3659  Int_t imx = Int_t(2.66*fMarkerSize + 0.5);
3660  shape[0].x =-imx; shape[0].y = 0;
3661  shape[1].x = 0; shape[1].y = -im;
3662  shape[2].x = imx; shape[2].y = 0;
3663  shape[3].x = 0; shape[3].y = im;
3664  shape[4].x =-imx; shape[4].y = 0;
3665  SetMarkerType(3,5,shape);
3666  } else if (fMarkerStyle == 34) {
3667  // full cross
3668  Int_t imx = Int_t(1.33*fMarkerSize + 0.5);
3669  shape[0].x = -im; shape[0].y =-imx;
3670  shape[1].x =-imx; shape[1].y =-imx;
3671  shape[2].x =-imx; shape[2].y = -im;
3672  shape[3].x = imx; shape[3].y = -im;
3673  shape[4].x = imx; shape[4].y =-imx;
3674  shape[5].x = im; shape[5].y =-imx;
3675  shape[6].x = im; shape[6].y = imx;
3676  shape[7].x = imx; shape[7].y = imx;
3677  shape[8].x = imx; shape[8].y = im;
3678  shape[9].x =-imx; shape[9].y = im;
3679  shape[10].x=-imx; shape[10].y= imx;
3680  shape[11].x= -im; shape[11].y= imx;
3681  shape[12].x= -im; shape[12].y=-imx;
3682  SetMarkerType(3,13,shape);
3683  } else if (fMarkerStyle == 35) {
3684  // square with diagonal cross
3685  shape[0].x = -im; shape[0].y = -im;
3686  shape[1].x = im; shape[1].y = -im;
3687  shape[2].x = im; shape[2].y = im;
3688  shape[3].x = -im; shape[3].y = im;
3689  shape[4].x = -im; shape[4].y = -im;
3690  shape[5].x = im; shape[5].y = im;
3691  shape[6].x = -im; shape[6].y = im;
3692  shape[7].x = im; shape[7].y = -im;
3693  SetMarkerType(2,8,shape);
3694  } else if (fMarkerStyle == 36) {
3695  // diamond with cross
3696  shape[0].x =-im; shape[0].y = 0;
3697  shape[1].x = 0; shape[1].y = -im;
3698  shape[2].x = im; shape[2].y = 0;
3699  shape[3].x = 0; shape[3].y = im;
3700  shape[4].x =-im; shape[4].y = 0;
3701  shape[5].x = im; shape[5].y = 0;
3702  shape[6].x = 0; shape[6].y = im;
3703  shape[7].x = 0; shape[7].y =-im;
3704  SetMarkerType(2,8,shape);
3705  } else if (fMarkerStyle == 37) {
3706  // open three triangles
3707  Int_t im2 = Int_t(2.0*fMarkerSize + 0.5);
3708  shape[0].x = 0; shape[0].y = 0;
3709  shape[1].x =-im2; shape[1].y = im;
3710  shape[2].x = -im; shape[2].y = 0;
3711  shape[3].x = 0; shape[3].y = 0;
3712  shape[4].x =-im2; shape[4].y = -im;
3713  shape[5].x = im2; shape[5].y = -im;
3714  shape[6].x = 0; shape[6].y = 0;
3715  shape[7].x = im; shape[7].y = 0;
3716  shape[8].x = im2; shape[8].y = im;
3717  shape[9].x = 0; shape[9].y = 0;
3718  SetMarkerType(2,10,shape);
3719  } else if (fMarkerStyle == 38) {
3720  // + shaped marker with octagon
3721  Int_t im2 = Int_t(2.0*fMarkerSize + 0.5);
3722  shape[0].x = -im; shape[0].y = 0;
3723  shape[1].x = -im; shape[1].y =-im2;
3724  shape[2].x =-im2; shape[2].y =-im;
3725  shape[3].x = im2; shape[3].y = -im;
3726  shape[4].x = im; shape[4].y =-im2;
3727  shape[5].x = im; shape[5].y = im2;
3728  shape[6].x = im2; shape[6].y = im;
3729  shape[7].x =-im2; shape[7].y = im;
3730  shape[8].x = -im; shape[8].y = im2;
3731  shape[9].x = -im; shape[9].y = 0;
3732  shape[10].x = im; shape[10].y = 0;
3733  shape[11].x = 0; shape[11].y = 0;
3734  shape[12].x = 0; shape[12].y = -im;
3735  shape[13].x = 0; shape[13].y = im;
3736  shape[14].x = 0; shape[14].y = 0;
3737  SetMarkerType(2,15,shape);
3738  } else if (fMarkerStyle == 39) {
3739  // filled three triangles
3740  Int_t im2 = Int_t(2.0*fMarkerSize + 0.5);
3741  shape[0].x = 0; shape[0].y = 0;
3742  shape[1].x =-im2; shape[1].y = im;
3743  shape[2].x = -im; shape[2].y = 0;
3744  shape[3].x = 0; shape[3].y = 0;
3745  shape[4].x =-im2; shape[4].y = -im;
3746  shape[5].x = im2; shape[5].y = -im;
3747  shape[6].x = 0; shape[6].y = 0;
3748  shape[7].x = im; shape[7].y = 0;
3749  shape[8].x = im2; shape[8].y = im;
3750  SetMarkerType(3,9,shape);
3751  } else if (fMarkerStyle == 40) {
3752  // four open triangles X
3753  Int_t im2 = Int_t(2.0*fMarkerSize + 0.5);
3754  shape[0].x = 0; shape[0].y = 0;
3755  shape[1].x = im2; shape[1].y = im;
3756  shape[2].x = im; shape[2].y = im2;
3757  shape[3].x = 0; shape[3].y = 0;
3758  shape[4].x = im; shape[4].y = -im2;
3759  shape[5].x = im2; shape[5].y = -im;
3760  shape[6].x = 0; shape[6].y = 0;
3761  shape[7].x = -im2; shape[7].y = -im;
3762  shape[8].x = -im; shape[8].y = -im2;
3763  shape[9].x = 0; shape[9].y = 0;
3764  shape[10].x = -im; shape[10].y = im2;
3765  shape[11].x = -im2; shape[11].y = im;
3766  shape[12].x = 0; shape[12].y = 0;
3767  SetMarkerType(2,13,shape);
3768  } else if (fMarkerStyle == 41) {
3769  // four filled triangles X
3770  Int_t im2 = Int_t(2.0*fMarkerSize + 0.5);
3771  shape[0].x = 0; shape[0].y = 0;
3772  shape[1].x = im2; shape[1].y = im;
3773  shape[2].x = im; shape[2].y = im2;
3774  shape[3].x = 0; shape[3].y = 0;
3775  shape[4].x = im; shape[4].y = -im2;
3776  shape[5].x = im2; shape[5].y = -im;
3777  shape[6].x = 0; shape[6].y = 0;
3778  shape[7].x = -im2; shape[7].y = -im;
3779  shape[8].x = -im; shape[8].y = -im2;
3780  shape[9].x = 0; shape[9].y = 0;
3781  shape[10].x = -im; shape[10].y = im2;
3782  shape[11].x = -im2; shape[11].y = im;
3783  shape[12].x = 0; shape[12].y = 0;
3784  SetMarkerType(3,13,shape);
3785  } else if (fMarkerStyle == 42) {
3786  // open double diamonds
3787  Int_t imx = Int_t(fMarkerSize + 0.5);
3788  shape[0].x= 0; shape[0].y= im;
3789  shape[1].x= -imx; shape[1].y= imx;
3790  shape[2].x = -im; shape[2].y = 0;
3791  shape[3].x = -imx; shape[3].y = -imx;
3792  shape[4].x = 0; shape[4].y = -im;
3793  shape[5].x = imx; shape[5].y = -imx;
3794  shape[6].x = im; shape[6].y = 0;
3795  shape[7].x= imx; shape[7].y= imx;
3796  shape[8].x= 0; shape[8].y= im;
3797  SetMarkerType(2,9,shape);
3798  } else if (fMarkerStyle == 43) {
3799  // filled double diamonds
3800  Int_t imx = Int_t(fMarkerSize + 0.5);
3801  shape[0].x = 0; shape[0].y = im;
3802  shape[1].x = -imx; shape[1].y = imx;
3803  shape[2].x = -im; shape[2].y = 0;
3804  shape[3].x = -imx; shape[3].y = -imx;
3805  shape[4].x = 0; shape[4].y = -im;
3806  shape[5].x = imx; shape[5].y = -imx;
3807  shape[6].x = im; shape[6].y = 0;
3808  shape[7].x = imx; shape[7].y = imx;
3809  shape[8].x = 0; shape[8].y = im;
3810  SetMarkerType(3,9,shape);
3811  } else if (fMarkerStyle == 44) {
3812  // open four triangles plus
3813  Int_t im2 = Int_t(2.0*fMarkerSize + 0.5);
3814  shape[0].x = 0; shape[0].y = 0;
3815  shape[1].x = im2; shape[1].y = im;
3816  shape[2].x = -im2; shape[2].y = im;
3817  shape[3].x = im2; shape[3].y = -im;
3818  shape[4].x = -im2; shape[4].y = -im;
3819  shape[5].x = 0; shape[5].y = 0;
3820  shape[6].x = im; shape[6].y = im2;
3821  shape[7].x = im; shape[7].y = -im2;
3822  shape[8].x = -im; shape[8].y = im2;
3823  shape[9].x = -im; shape[9].y = -im2;
3824  shape[10].x = 0; shape[10].y = 0;
3825  SetMarkerType(2,11,shape);
3826  } else if (fMarkerStyle == 45) {
3827  // filled four triangles plus
3828  Int_t im0 = Int_t(0.4*fMarkerSize + 0.5);
3829  Int_t im2 = Int_t(2.0*fMarkerSize + 0.5);
3830  shape[0].x = im0; shape[0].y = im0;
3831  shape[1].x = im2; shape[1].y = im;
3832  shape[2].x = -im2; shape[2].y = im;
3833  shape[3].x = -im0; shape[3].y = im0;
3834  shape[4].x = -im; shape[4].y = im2;
3835  shape[5].x = -im; shape[5].y = -im2;
3836  shape[6].x = -im0; shape[6].y = -im0;
3837  shape[7].x = -im2; shape[7].y = -im;
3838  shape[8].x = im2; shape[8].y = -im;
3839  shape[9].x = im0; shape[9].y = -im0;
3840  shape[10].x = im; shape[10].y = -im2;
3841  shape[11].x = im; shape[11].y = im2;
3842  shape[12].x = im0; shape[12].y = im0;
3843  SetMarkerType(3,13,shape);
3844  } else if (fMarkerStyle == 46) {
3845  // open four triangles X
3846  Int_t im2 = Int_t(2.0*fMarkerSize + 0.5);
3847  shape[0].x = 0; shape[0].y = im2;
3848  shape[1].x = -im2; shape[1].y = im;
3849  shape[2].x = -im; shape[2].y = im2;
3850  shape[3].x = -im2; shape[3].y = 0;
3851  shape[4].x = -im; shape[4].y = -im2;
3852  shape[5].x = -im2; shape[5].y = -im;
3853  shape[6].x = 0; shape[6].y = -im2;
3854  shape[7].x = im2; shape[7].y = -im;
3855  shape[8].x = im; shape[8].y = -im2;
3856  shape[9].x = im2; shape[9].y = 0;
3857  shape[10].x = im; shape[10].y = im2;
3858  shape[11].x = im2; shape[11].y = im;
3859  shape[12].x = 0; shape[12].y = im2;
3860  SetMarkerType(2,13,shape);
3861  } else if (fMarkerStyle == 47) {
3862  // filled four triangles X
3863  Int_t im2 = Int_t(2.0*fMarkerSize + 0.5);
3864  shape[0].x = 0; shape[0].y = im2;
3865  shape[1].x = -im2; shape[1].y = im;
3866  shape[2].x = -im; shape[2].y = im2;
3867  shape[3].x = -im2; shape[3].y = 0;
3868  shape[4].x = -im; shape[4].y = -im2;
3869  shape[5].x = -im2; shape[5].y = -im;
3870  shape[6].x = 0; shape[6].y = -im2;
3871  shape[7].x = im2; shape[7].y = -im;
3872  shape[8].x = im; shape[8].y = -im2;
3873  shape[9].x = im2; shape[9].y = 0;
3874  shape[10].x = im; shape[10].y = im2;
3875  shape[11].x = im2; shape[11].y = im;
3876  shape[12].x = 0; shape[12].y = im2;
3877  SetMarkerType(3,13,shape);
3878  } else if (fMarkerStyle == 48) {
3879  // four filled squares X
3880  Int_t im2 = Int_t(2.0*fMarkerSize + 0.5);
3881  shape[0].x = 0; shape[0].y = im2*1.005;
3882  shape[1].x = -im2; shape[1].y = im;
3883  shape[2].x = -im; shape[2].y = im2;
3884  shape[3].x = -im2; shape[3].y = 0;
3885  shape[4].x = -im; shape[4].y = -im2;
3886  shape[5].x = -im2; shape[5].y = -im;
3887  shape[6].x = 0; shape[6].y = -im2;
3888  shape[7].x = im2; shape[7].y = -im;
3889  shape[8].x = im; shape[8].y = -im2;
3890  shape[9].x = im2; shape[9].y = 0;
3891  shape[10].x = im; shape[10].y = im2;
3892  shape[11].x = im2; shape[11].y = im;
3893  shape[12].x = 0; shape[12].y = im2*0.995;
3894  shape[13].x = im2*0.995; shape[13].y = 0;
3895  shape[14].x = 0; shape[14].y = -im2*0.995;
3896  shape[15].x = -im2*0.995; shape[15].y = 0;
3897  shape[16].x = 0; shape[16].y = im2*0.995;
3898  SetMarkerType(3,16,shape);
3899  } else if (fMarkerStyle == 49) {
3900  // four filled squares plus
3901  Int_t imx = Int_t(1.33*fMarkerSize + 0.5);
3902  shape[0].x =-imx; shape[0].y =-imx*1.005;
3903  shape[1].x =-imx; shape[1].y = -im;
3904  shape[2].x = imx; shape[2].y = -im;
3905  shape[3].x = imx; shape[3].y =-imx;
3906  shape[4].x = im; shape[4].y =-imx;
3907  shape[5].x = im; shape[5].y = imx;
3908  shape[6].x = imx; shape[6].y = imx;
3909  shape[7].x = imx; shape[7].y = im;
3910  shape[8].x =-imx; shape[8].y = im;
3911  shape[9].x =-imx; shape[9].y = imx;
3912  shape[10].x = -im; shape[10].y = imx;
3913  shape[11].x = -im; shape[11].y =-imx;
3914  shape[12].x =-imx; shape[12].y =-imx*0.995;
3915  shape[13].x =-imx; shape[13].y = imx;
3916  shape[14].x = imx; shape[14].y = imx;
3917  shape[15].x = imx; shape[15].y =-imx;
3918  shape[16].x =-imx; shape[16].y =-imx*1.005;
3919  SetMarkerType(3,17,shape);
3920  } else {
3921  // single dot
3922  SetMarkerType(0, 0, shape);
3923  }
3924  fMarkerStyleModified = kFALSE;
3925 }
3926 
3927 ////////////////////////////////////////////////////////////////////////////////
3928 /// Set opacity of a window. This image manipulation routine works
3929 /// by adding to a percent amount of neutral to each pixels RGB.
3930 /// Since it requires quite some additional color map entries is it
3931 /// only supported on displays with more than > 8 color planes (> 256
3932 /// colors)
3933 
3934 void TGWin32::SetOpacity(Int_t percent)
3935 {
3936  Int_t depth = gdk_visual_get_best_depth();
3937 
3938  if (depth <= 8) return;
3939  if (percent == 0) return;
3940 
3941  // if 100 percent then just make white
3942  ULong_t *orgcolors = 0, *tmpc = 0;
3943  Int_t maxcolors = 0, ncolors, ntmpc = 0;
3944 
3945  // save previous allocated colors, delete at end when not used anymore
3946  if (gCws->new_colors) {
3947  tmpc = gCws->new_colors;
3948  ntmpc = gCws->ncolors;
3949  }
3950  // get pixmap from server as image
3951  GdkImage *image = gdk_image_get((GdkDrawable*)gCws->drawing, 0, 0,
3952  gCws->width, gCws->height);
3953 
3954  // collect different image colors
3955  int x, y;
3956  for (y = 0; y < (int) gCws->height; y++) {
3957  for (x = 0; x < (int) gCws->width; x++) {
3958  ULong_t pixel = GetPixelImage((Drawable_t)image, x, y);
3959  CollectImageColors(pixel, orgcolors, ncolors, maxcolors);
3960  }
3961  }
3962  if (ncolors == 0) {
3963  gdk_image_unref(image);
3964  ::operator delete(orgcolors);
3965  return;
3966  }
3967  // create opaque counter parts
3968  MakeOpaqueColors(percent, orgcolors, ncolors);
3969 
3970  // put opaque colors in image
3971  for (y = 0; y < (int) gCws->height; y++) {
3972  for (x = 0; x < (int) gCws->width; x++) {
3973  ULong_t pixel = GetPixelImage((Drawable_t)image, x, y);
3974  Int_t idx = FindColor(pixel, orgcolors, ncolors);
3975  PutPixel((Drawable_t)image, x, y, gCws->new_colors[idx]);
3976  }
3977  }
3978 
3979  // put image back in pixmap on server
3980  gdk_draw_image(gCws->drawing, gGCpxmp, (GdkImage *)image,
3981  0, 0, 0, 0, gCws->width, gCws->height);
3982  GdiFlush();
3983 
3984  // clean up
3985  if (tmpc) {
3986  gdk_colors_free((GdkColormap *)fColormap, tmpc, ntmpc, 0);
3987  delete[]tmpc;
3988  }
3989  gdk_image_unref(image);
3990  ::operator delete(orgcolors);
3991 }
3992 
3993 ////////////////////////////////////////////////////////////////////////////////
3994 /// Get RGB values for orgcolors, add percent neutral to the RGB and
3995 /// allocate new_colors.
3996 
3997 void TGWin32::MakeOpaqueColors(Int_t percent, ULong_t *orgcolors, Int_t ncolors)
3998 {
3999  Int_t ret;
4000  if (ncolors <= 0) return;
4001  GdkColor *xcol = new GdkColor[ncolors];
4002 
4003  int i;
4004  for (i = 0; i < ncolors; i++) {
4005  xcol[i].pixel = orgcolors[i];
4006  xcol[i].red = xcol[i].green = xcol[i].blue = 0;
4007  }
4008 
4009  GdkColorContext *cc;
4010  cc = gdk_color_context_new(gdk_visual_get_system(), (GdkColormap *)fColormap);
4011  gdk_color_context_query_colors(cc, xcol, ncolors);
4012  gdk_color_context_free(cc);
4013 
4014  UShort_t add = percent * kBIGGEST_RGB_VALUE / 100;
4015 
4016  Int_t val;
4017  for (i = 0; i < ncolors; i++) {
4018  val = xcol[i].red + add;
4019  if (val > kBIGGEST_RGB_VALUE) {
4020  val = kBIGGEST_RGB_VALUE;
4021  }
4022  xcol[i].red = (UShort_t) val;
4023  val = xcol[i].green + add;
4024  if (val > kBIGGEST_RGB_VALUE) {
4025  val = kBIGGEST_RGB_VALUE;
4026  }
4027  xcol[i].green = (UShort_t) val;
4028  val = xcol[i].blue + add;
4029  if (val > kBIGGEST_RGB_VALUE) {
4030  val = kBIGGEST_RGB_VALUE;
4031  }
4032  xcol[i].blue = (UShort_t) val;
4033 
4034  ret = gdk_color_alloc((GdkColormap *)fColormap, &xcol[i]);
4035 
4036  if (!ret) {
4037  Warning("MakeOpaqueColors",
4038  "failed to allocate color %hd, %hd, %hd", xcol[i].red,
4039  xcol[i].green, xcol[i].blue);
4040  // assumes that in case of failure xcol[i].pixel is not changed
4041  }
4042  }
4043 
4044  gCws->new_colors = new ULong_t[ncolors];
4045  gCws->ncolors = ncolors;
4046 
4047  for (i = 0; i < ncolors; i++) {
4048  gCws->new_colors[i] = xcol[i].pixel;
4049  }
4050 
4051  delete []xcol;
4052 }
4053 
4054 ////////////////////////////////////////////////////////////////////////////////
4055 /// Returns index in orgcolors (and new_colors) for pixel.
4056 
4057 Int_t TGWin32::FindColor(ULong_t pixel, ULong_t * orgcolors, Int_t ncolors)
4058 {
4059  for (int i = 0; i < ncolors; i++) {
4060  if (pixel == orgcolors[i]) return i;
4061  }
4062  Error("FindColor", "did not find color, should never happen!");
4063 
4064  return 0;
4065 }
4066 
4067 ////////////////////////////////////////////////////////////////////////////////
4068 /// Set color intensities for given color index.
4069 /// cindex : color index
4070 /// r,g,b : red, green, blue intensities between 0.0 and 1.0
4071 
4072 void TGWin32::SetRGB(int cindex, float r, float g, float b)
4073 {
4074  GdkColor xcol;
4075 
4076  if (fColormap && cindex >= 0) {
4077  xcol.red = (unsigned short) (r * kBIGGEST_RGB_VALUE);
4078  xcol.green = (unsigned short) (g * kBIGGEST_RGB_VALUE);
4079  xcol.blue = (unsigned short) (b * kBIGGEST_RGB_VALUE);
4080  xcol.pixel = RGB(xcol.red, xcol.green, xcol.blue);
4081 
4082  XColor_t &col = GetColor(cindex);
4083  if (col.fDefined) {
4084  // if color is already defined with same rgb just return
4085  if (col.color.red == xcol.red && col.color.green == xcol.green &&
4086  col.color.blue == xcol.blue)
4087  return;
4088  col.fDefined = kFALSE;
4089  gdk_colormap_free_colors((GdkColormap *) fColormap,
4090  (GdkColor *)&col, 1);
4091  }
4092 
4093  Int_t ret = gdk_colormap_alloc_color(fColormap, &xcol, 1, 1);
4094  if (ret != 0) {
4095  col.fDefined = kTRUE;
4096  col.color.pixel = xcol.pixel;
4097  col.color.red = xcol.red;
4098  col.color.green = xcol.green;
4099  col.color.blue = xcol.blue;
4100  }
4101  }
4102 }
4103 
4104 ////////////////////////////////////////////////////////////////////////////////
4105 /// Set text alignment.
4106 /// txalh : horizontal text alignment
4107 /// txalv : vertical text alignment
4108 
4109 void TGWin32::SetTextAlign(Short_t talign)
4110 {
4111  static Short_t current = 0;
4112  if (talign==current) return;
4113  current = talign;
4114 
4115  Int_t txalh = talign / 10;
4116  Int_t txalv = talign % 10;
4117  fTextAlignH = txalh;
4118  fTextAlignV = txalv;
4119 
4120  switch (txalh) {
4121 
4122  case 0:
4123  case 1:
4124  switch (txalv) { //left
4125  case 1:
4126  fTextAlign = 7; //bottom
4127  break;
4128  case 2:
4129  fTextAlign = 4; //center
4130  break;
4131  case 3:
4132  fTextAlign = 1; //top
4133  break;
4134  }
4135  break;
4136  case 2:
4137  switch (txalv) { //center
4138  case 1:
4139  fTextAlign = 8; //bottom
4140  break;
4141  case 2:
4142  fTextAlign = 5; //center
4143  break;
4144  case 3:
4145  fTextAlign = 2; //top
4146  break;
4147  }
4148  break;
4149  case 3:
4150  switch (txalv) { //right
4151  case 1:
4152  fTextAlign = 9; //bottom
4153  break;
4154  case 2:
4155  fTextAlign = 6; //center
4156  break;
4157  case 3:
4158  fTextAlign = 3; //top
4159  break;
4160  }
4161  break;
4162  }
4163  TAttText::SetTextAlign(fTextAlign);
4164 }
4165 
4166 ////////////////////////////////////////////////////////////////////////////////
4167 /// Set color index for text.
4168 
4169 void TGWin32::SetTextColor(Color_t cindex)
4170 {
4171  static Int_t current = 0;
4172  GdkGCValues values;
4173  if ((cindex < 0) || (Int_t(cindex)==current)) return;
4174 
4175  TAttText::SetTextColor(cindex);
4176 
4177  SetColor(gGCtext, Int_t(cindex));
4178  gdk_gc_get_values(gGCtext, &values);
4179  gdk_gc_set_foreground(gGCinvt, &values.background);
4180  gdk_gc_set_background(gGCinvt, &values.foreground);
4181  gdk_gc_set_background(gGCtext, (GdkColor *) & GetColor(0).color);
4182  current = Int_t(cindex);
4183 }
4184 
4185 ////////////////////////////////////////////////////////////////////////////////
4186 
4187 void TGWin32::Sync(int mode)
4188 {
4189 }
4190 
4191 ////////////////////////////////////////////////////////////////////////////////
4192 /// Update display.
4193 /// mode : (1) update
4194 /// (0) sync
4195 ///
4196 /// Synchronise client and server once (not permanent).
4197 /// Copy the pixmap gCws->drawing on the window gCws->window
4198 /// if the double buffer is on.
4199 
4200 void TGWin32::UpdateWindow(int mode)
4201 {
4202  if (gCws && gCws->double_buffer) {
4203  gdk_window_copy_area(gCws->window, gGCpxmp, 0, 0,
4204  gCws->drawing, 0, 0, gCws->width, gCws->height);
4205  }
4206  Update(mode);
4207 }
4208 
4209 ////////////////////////////////////////////////////////////////////////////////
4210 /// Set pointer position.
4211 /// ix : New X coordinate of pointer
4212 /// iy : New Y coordinate of pointer
4213 /// Coordinates are relative to the origin of the window id
4214 /// or to the origin of the current window if id == 0.
4215 
4216 void TGWin32::Warp(int ix, int iy, Window_t id)
4217 {
4218  if (!id) return;
4219 
4220  POINT cpt, tmp;
4221  HWND dw;
4222  if (!id)
4223  dw = (HWND) GDK_DRAWABLE_XID((GdkWindow *)gCws->window);
4224  else
4225  dw = (HWND) GDK_DRAWABLE_XID((GdkWindow *)id);
4226  GetCursorPos(&cpt);
4227  tmp.x = ix > 0 ? ix : cpt.x;
4228  tmp.y = iy > 0 ? iy : cpt.y;
4229  ClientToScreen(dw, &tmp);
4230  SetCursorPos(tmp.x, tmp.y);
4231 }
4232 
4233 ////////////////////////////////////////////////////////////////////////////////
4234 /// Write the pixmap wid in the bitmap file pxname.
4235 /// wid : Pixmap address
4236 /// w,h : Width and height of the pixmap.
4237 /// lenname : pixmap name length
4238 /// pxname : pixmap name
4239 
4240 void TGWin32::WritePixmap(int wid, unsigned int w, unsigned int h,
4241  char *pxname)
4242 {
4243  int wval, hval;
4244  wval = w;
4245  hval = h;
4246 
4247  if (!fWindows) return;
4248  gTws = &fWindows[wid];
4249 // XWriteBitmapFile(fDisplay,pxname,(Pixmap)gTws->drawing,wval,hval,-1,-1);
4250 }
4251 
4252 
4253 //
4254 // Functions for GIFencode()
4255 //
4256 
4257 static FILE *gGifFile; // output unit used WriteGIF and PutByte
4258 static GdkImage *gGifImage = 0; // image used in WriteGIF and GetPixel
4259 
4260 extern "C" {
4261  int GIFquantize(UInt_t width, UInt_t height, Int_t * ncol, Byte_t * red,
4262  Byte_t * green, Byte_t * blue, Byte_t * outputBuf,
4263  Byte_t * outputCmap);
4264  long GIFencode(int Width, int Height, Int_t Ncol, Byte_t R[],
4265  Byte_t G[], Byte_t B[], Byte_t ScLine[],
4266  void (*get_scline) (int, int, Byte_t *),
4267  void (*pb) (Byte_t));
4268  int GIFdecode(Byte_t * GIFarr, Byte_t * PIXarr, int *Width, int *Height,
4269  int *Ncols, Byte_t * R, Byte_t * G, Byte_t * B);
4270  int GIFinfo(Byte_t * GIFarr, int *Width, int *Height, int *Ncols);
4271 }
4272 
4273 
4274 ////////////////////////////////////////////////////////////////////////////////
4275 /// Get pixels in line y and put in array scline.
4276 
4277 static void GetPixel(int y, int width, Byte_t * scline)
4278 {
4279  for (int i = 0; i < width; i++) {
4280  scline[i] = Byte_t(GetPixelImage((Drawable_t)gGifImage, i, y));
4281  }
4282 }
4283 
4284 ////////////////////////////////////////////////////////////////////////////////
4285 /// Put byte b in output stream.
4286 
4287 static void PutByte(Byte_t b)
4288 {
4289  if (ferror(gGifFile) == 0) fputc(b, gGifFile);
4290 }
4291 
4292 ////////////////////////////////////////////////////////////////////////////////
4293 /// Returns in R G B the ncol colors of the palette used by the image.
4294 /// The image pixels are changed to index values in these R G B arrays.
4295 /// This produces a colormap with only the used colors (so even on displays
4296 /// with more than 8 planes we will be able to create GIF's when the image
4297 /// contains no more than 256 different colors). If it does contain more
4298 /// colors we will have to use GIFquantize to reduce the number of colors.
4299 /// The R G B arrays must be deleted by the caller.
4300 
4301 void TGWin32::ImgPickPalette(GdkImage * image, Int_t & ncol, Int_t * &R,
4302  Int_t * &G, Int_t * &B)
4303 {
4304  ULong_t *orgcolors = 0;
4305  Int_t maxcolors = 0, ncolors;
4306 
4307  // collect different image colors
4308  int x, y;
4309  for (x = 0; x < (int) gCws->width; x++) {
4310  for (y = 0; y < (int) gCws->height; y++) {
4311  ULong_t pixel = GetPixelImage((Drawable_t)image, x, y);
4312  CollectImageColors(pixel, orgcolors, ncolors, maxcolors);
4313  }
4314  }
4315 
4316  // get RGB values belonging to pixels
4317  GdkColor *xcol = new GdkColor[ncolors];
4318 
4319  int i;
4320  for (i = 0; i < ncolors; i++) {
4321  xcol[i].pixel = orgcolors[i];
4322 // xcol[i].red = xcol[i].green = xcol[i].blue = 0;
4323  xcol[i].red = GetRValue(xcol[i].pixel);
4324  xcol[i].green = GetGValue(xcol[i].pixel);
4325  xcol[i].blue = GetBValue(xcol[i].pixel);
4326  }
4327 
4328  GdkColorContext *cc;
4329  cc = gdk_color_context_new(gdk_visual_get_system(), (GdkColormap *)fColormap);
4330  gdk_color_context_query_colors(cc, xcol, ncolors);
4331  gdk_color_context_free(cc);
4332 
4333  // create RGB arrays and store RGB's for each color and set number of colors
4334  // (space must be delete by caller)
4335  R = new Int_t[ncolors];
4336  G = new Int_t[ncolors];
4337  B = new Int_t[ncolors];
4338 
4339  for (i = 0; i < ncolors; i++) {
4340  R[i] = xcol[i].red;
4341  G[i] = xcol[i].green;
4342  B[i] = xcol[i].blue;
4343  }
4344  ncol = ncolors;
4345 
4346  // update image with indices (pixels) into the new RGB colormap
4347  for (x = 0; x < (int) gCws->width; x++) {
4348  for (y = 0; y < (int) gCws->height; y++) {
4349  ULong_t pixel = GetPixelImage((Drawable_t)image, x, y);
4350  Int_t idx = FindColor(pixel, orgcolors, ncolors);
4351  PutPixel((Drawable_t)image, x, y, idx);
4352  }
4353  }
4354 
4355  // cleanup
4356  delete[]xcol;
4357  ::operator delete(orgcolors);
4358 }
4359 
4360 ////////////////////////////////////////////////////////////////////////////////
4361 /// Writes the current window into GIF file.
4362 
4363 Int_t TGWin32::WriteGIF(char *name)
4364 {
4365  Byte_t scline[2000], r[256], b[256], g[256];
4366  Int_t *R, *G, *B;
4367  Int_t ncol, maxcol, i;
4368 
4369  if (gGifImage) {
4370  gdk_image_unref((GdkImage *)gGifImage);
4371  }
4372 
4373  gGifImage = gdk_image_get((GdkDrawable*)gCws->drawing, 0, 0,
4374  gCws->width, gCws->height);
4375 
4376  ImgPickPalette(gGifImage, ncol, R, G, B);
4377 
4378  if (ncol > 256) {
4379  //GIFquantize(...);
4380  Error("WriteGIF",
4381  "can not create GIF of image containing more than 256 colors");
4382  delete[]R;
4383  delete[]G;
4384  delete[]B;
4385  return 0;
4386  }
4387 
4388  maxcol = 0;
4389  for (i = 0; i < ncol; i++) {
4390  if (maxcol < R[i]) maxcol = R[i];
4391  if (maxcol < G[i]) maxcol = G[i];
4392  if (maxcol < B[i]) maxcol = B[i];
4393  r[i] = 0;
4394  g[i] = 0;
4395  b[i] = 0;
4396  }
4397  if (maxcol != 0) {
4398  for (i = 0; i < ncol; i++) {
4399  r[i] = R[i] * 255 / maxcol;
4400  g[i] = G[i] * 255 / maxcol;
4401  b[i] = B[i] * 255 / maxcol;
4402  }
4403  }
4404 
4405  gGifFile = fopen(name, "wb");
4406 
4407  if (gGifFile) {
4408  GIFencode(gCws->width, gCws->height,
4409  ncol, r, g, b, scline, ::GetPixel, PutByte);
4410  fclose(gGifFile);
4411  i = 1;
4412  } else {
4413  Error("WriteGIF","cannot write file: %s",name);
4414  i = 0;
4415  }
4416  delete[]R;
4417  delete[]G;
4418  delete[]B;
4419 
4420  return i;
4421 }
4422 
4423 ////////////////////////////////////////////////////////////////////////////////
4424 /// Draw image.
4425 
4426 void TGWin32::PutImage(int offset, int itran, int x0, int y0, int nx,
4427  int ny, int xmin, int ymin, int xmax, int ymax,
4428  unsigned char *image, Drawable_t wid)
4429 {
4430  const int MAX_SEGMENT = 20;
4431  int i, n, x, y, xcur, x1, x2, y1, y2;
4432  unsigned char *jimg, *jbase, icol;
4433  int nlines[256];
4434  GdkSegment lines[256][MAX_SEGMENT];
4435  GdkDrawable *id;
4436 
4437  if (wid) {
4438  id = (GdkDrawable*)wid;
4439  } else {
4440  id = gCws->drawing;
4441  }
4442 
4443  for (i = 0; i < 256; i++) nlines[i] = 0;
4444 
4445  x1 = x0 + xmin;
4446  y1 = y0 + ny - ymax - 1;
4447  x2 = x0 + xmax;
4448  y2 = y0 + ny - ymin - 1;
4449  jbase = image + (ymin - 1) * nx + xmin;
4450 
4451  for (y = y2; y >= y1; y--) {
4452  xcur = x1;
4453  jbase += nx;
4454  for (jimg = jbase, icol = *jimg++, x = x1 + 1; x <= x2; jimg++, x++) {
4455  if (icol != *jimg) {
4456  if (icol != itran) {
4457  n = nlines[icol]++;
4458  lines[icol][n].x1 = xcur;
4459  lines[icol][n].y1 = y;
4460  lines[icol][n].x2 = x - 1;
4461  lines[icol][n].y2 = y;
4462  if (nlines[icol] == MAX_SEGMENT) {
4463  SetColor(gGCline, (int) icol + offset);
4464  gdk_win32_draw_segments(id, (GdkGC *) gGCline,
4465  (GdkSegment *) &lines[icol][0], MAX_SEGMENT);
4466  nlines[icol] = 0;
4467  }
4468  }
4469  icol = *jimg;
4470  xcur = x;
4471  }
4472  }
4473  if (icol != itran) {
4474  n = nlines[icol]++;
4475  lines[icol][n].x1 = xcur;
4476  lines[icol][n].y1 = y;
4477  lines[icol][n].x2 = x - 1;
4478  lines[icol][n].y2 = y;
4479  if (nlines[icol] == MAX_SEGMENT) {
4480  SetColor(gGCline, (int) icol + offset);
4481  gdk_win32_draw_segments(id, (GdkGC *) gGCline,
4482  (GdkSegment *)&lines[icol][0], MAX_SEGMENT);
4483  nlines[icol] = 0;
4484  }
4485  }
4486  }
4487 
4488  for (i = 0; i < 256; i++) {
4489  if (nlines[i] != 0) {
4490  SetColor(gGCline, i + offset);
4491  gdk_win32_draw_segments(id, (GdkGC *) gGCline,
4492  (GdkSegment *)&lines[icol][0], nlines[i]);
4493  }
4494  }
4495 }
4496 
4497 ////////////////////////////////////////////////////////////////////////////////
4498 /// If id is NULL - loads the specified gif file at position [x0,y0] in the
4499 /// current window. Otherwise creates pixmap from gif file
4500 
4501 Pixmap_t TGWin32::ReadGIF(int x0, int y0, const char *file, Window_t id)
4502 {
4503  FILE *fd;
4504  Seek_t filesize;
4505  unsigned char *GIFarr, *PIXarr, R[256], G[256], B[256], *j1, *j2, icol;
4506  int i, j, k, width, height, ncolor, irep, offset;
4507  float rr, gg, bb;
4508  Pixmap_t pic = 0;
4509 
4510  fd = fopen(file, "r+b");
4511  if (!fd) {
4512  Error("ReadGIF", "unable to open GIF file");
4513  return pic;
4514  }
4515 
4516  fseek(fd, 0L, 2);
4517  filesize = Seek_t(ftell(fd));
4518  fseek(fd, 0L, 0);
4519 
4520  if (!(GIFarr = (unsigned char *) calloc(filesize + 256, 1))) {
4521  fclose(fd);
4522  Error("ReadGIF", "unable to allocate array for gif");
4523  return pic;
4524  }
4525 
4526  if (fread(GIFarr, filesize, 1, fd) != 1) {
4527  fclose(fd);
4528  Error("ReadGIF", "GIF file read failed");
4529  free(GIFarr);
4530  return pic;
4531  }
4532  fclose(fd);
4533 
4534  irep = GIFinfo(GIFarr, &width, &height, &ncolor);
4535  if (irep != 0) {
4536  return pic;
4537  }
4538 
4539  if (!(PIXarr = (unsigned char *) calloc((width * height), 1))) {
4540  Error("ReadGIF", "unable to allocate array for image");
4541  return pic;
4542  }
4543 
4544  irep = GIFdecode(GIFarr, PIXarr, &width, &height, &ncolor, R, G, B);
4545  if (irep != 0) {
4546  return pic;
4547  }
4548  // S E T P A L E T T E
4549 
4550  offset = 8;
4551 
4552  for (i = 0; i < ncolor; i++) {
4553  rr = R[i] / 255.;
4554  gg = G[i] / 255.;
4555  bb = B[i] / 255.;
4556  j = i + offset;
4557  SetRGB(j, rr, gg, bb);
4558  }
4559 
4560  // O U T P U T I M A G E
4561 
4562  for (i = 1; i <= height / 2; i++) {
4563  j1 = PIXarr + (i - 1) * width;
4564  j2 = PIXarr + (height - i) * width;
4565  for (k = 0; k < width; k++) {
4566  icol = *j1;
4567  *j1++ = *j2;
4568  *j2++ = icol;
4569  }
4570  }
4571 
4572  if (id) pic = CreatePixmap(id, width, height);
4573  PutImage(offset, -1, x0, y0, width, height, 0, 0, width-1, height-1, PIXarr, pic);
4574 
4575  if (pic) return pic;
4576  else if (gCws->drawing) return (Pixmap_t)gCws->drawing;
4577  else return 0;
4578 }
4579 
4580 //////////////////////////// GWin32Gui //////////////////////////////////////////
4581 ////////////////////////////////////////////////////////////////////////////////
4582 /// Map window on screen.
4583 
4584 void TGWin32::MapWindow(Window_t id)
4585 {
4586  if (!id) return;
4587 
4588  gdk_window_show((GdkWindow *)id);
4589  if ((GDK_DRAWABLE_TYPE((GdkWindow *)id) != GDK_WINDOW_TEMP) &&
4590  (GetParent(id) == GetDefaultRootWindow())) {
4591  HWND window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)id);
4592  ::SetForegroundWindow(window);
4593  }
4594 }
4595 
4596 ////////////////////////////////////////////////////////////////////////////////
4597 ///
4598 
4599 void TGWin32::MapSubwindows(Window_t id)
4600 {
4601  if (!id) return;
4602 
4603  EnumChildWindows((HWND)GDK_DRAWABLE_XID((GdkWindow *)id),
4604  EnumChildProc, (LPARAM) NULL);
4605 }
4606 
4607 ////////////////////////////////////////////////////////////////////////////////
4608 /// Map window on screen and put on top of all windows.
4609 
4610 void TGWin32::MapRaised(Window_t id)
4611 {
4612  if (!id) return;
4613 
4614  HWND hwnd = ::GetForegroundWindow();
4615  HWND window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)id);
4616  gdk_window_show((GdkWindow *)id);
4617  if (GDK_DRAWABLE_TYPE((GdkWindow *)id) != GDK_WINDOW_TEMP) {
4618  ::BringWindowToTop(window);
4619  if (GDK_DRAWABLE_TYPE((GdkWindow *)id) != GDK_WINDOW_CHILD)
4620  ::SetForegroundWindow(window);
4621  }
4622 
4623  if (gConsoleWindow && (hwnd == (HWND)gConsoleWindow)) {
4624  RECT r1, r2, r3;
4625  ::GetWindowRect((HWND)gConsoleWindow, &r1);
4626  HWND fore = ::GetForegroundWindow();
4627  ::GetWindowRect(fore, &r2);
4628  if (!::IntersectRect(&r3, &r2, &r1)) {
4629  ::SetForegroundWindow((HWND)gConsoleWindow);
4630  }
4631  }
4632 }
4633 
4634 ////////////////////////////////////////////////////////////////////////////////
4635 /// Unmap window from screen.
4636 
4637 void TGWin32::UnmapWindow(Window_t id)
4638 {
4639  if (!id) return;
4640 
4641  gdk_window_hide((GdkWindow *) id);
4642 }
4643 
4644 ////////////////////////////////////////////////////////////////////////////////
4645 /// Destroy window.
4646 
4647 void TGWin32::DestroyWindow(Window_t id)
4648 {
4649  if (!id) return;
4650 
4651  // we need to unmap the window before to destroy it, in order to properly
4652  // receive kUnmapNotify needed by gClient->WaitForUnmap()...
4653  gdk_window_hide((GdkWindow *) id);
4654  gdk_window_destroy((GdkDrawable *) id, kTRUE);
4655 }
4656 
4657 ////////////////////////////////////////////////////////////////////////////////
4658 /// Destroy all internal subwindows
4659 
4660 void TGWin32::DestroySubwindows(Window_t id)
4661 {
4662  if (!id) return;
4663 
4664  gdk_window_destroy((GdkDrawable *) id, kFALSE);
4665 }
4666 
4667 ////////////////////////////////////////////////////////////////////////////////
4668 /// Put window on top of window stack.
4669 
4670 void TGWin32::RaiseWindow(Window_t id)
4671 {
4672  if (!id) return;
4673 
4674  HWND window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)id);
4675  if (GDK_DRAWABLE_TYPE((GdkWindow *)id) == GDK_WINDOW_TEMP) {
4676  ::SetWindowPos(window, HWND_TOPMOST, 0, 0, 0, 0,
4677  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
4678  }
4679  else {
4680  ::BringWindowToTop(window);
4681  if (GDK_DRAWABLE_TYPE((GdkWindow *)id) != GDK_WINDOW_CHILD)
4682  ::SetForegroundWindow(window);
4683  }
4684 }
4685 
4686 ////////////////////////////////////////////////////////////////////////////////
4687 /// Lower window so it lays below all its siblings.
4688 
4689 void TGWin32::LowerWindow(Window_t id)
4690 {
4691  if (!id) return;
4692 
4693  HWND window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)id);
4694  ::SetWindowPos(window, HWND_BOTTOM, 0, 0, 0, 0,
4695  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
4696 }
4697 
4698 ////////////////////////////////////////////////////////////////////////////////
4699 /// Move a window.
4700 
4701 void TGWin32::MoveWindow(Window_t id, Int_t x, Int_t y)
4702 {
4703  if (!id) return;
4704 
4705  gdk_window_move((GdkDrawable *) id, x, y);
4706 }
4707 
4708 ////////////////////////////////////////////////////////////////////////////////
4709 /// Move and resize a window.
4710 
4711 void TGWin32::MoveResizeWindow(Window_t id, Int_t x, Int_t y, UInt_t w,
4712  UInt_t h)
4713 {
4714  if (!id) return;
4715 
4716  gdk_window_move_resize((GdkWindow *) id, x, y, w, h);
4717 }
4718 
4719 ////////////////////////////////////////////////////////////////////////////////
4720 /// Resize the window.
4721 
4722 void TGWin32::ResizeWindow(Window_t id, UInt_t w, UInt_t h)
4723 {
4724  if (!id) return;
4725 
4726  // protect against potential negative values
4727  if (w >= (UInt_t)INT_MAX || h >= (UInt_t)INT_MAX)
4728  return;
4729  gdk_window_resize((GdkWindow *) id, w, h);
4730 }
4731 
4732 ////////////////////////////////////////////////////////////////////////////////
4733 /// Iconify the window.
4734 
4735 void TGWin32::IconifyWindow(Window_t id)
4736 {
4737  if (!id) return;
4738 
4739  gdk_window_lower((GdkWindow *) id);
4740  ::CloseWindow((HWND)GDK_DRAWABLE_XID((GdkWindow *)id));
4741 }
4742 
4743 ////////////////////////////////////////////////////////////////////////////////
4744 /// Reparent window, make pid the new parent and position the window at
4745 /// position (x,y) in new parent.
4746 
4747 void TGWin32::ReparentWindow(Window_t id, Window_t pid, Int_t x, Int_t y)
4748 {
4749  if (!id) return;
4750 
4751  gdk_window_reparent((GdkWindow *)id, (GdkWindow *)pid, x, y);
4752 }
4753 
4754 ////////////////////////////////////////////////////////////////////////////////
4755 /// Set the window background color.
4756 
4757 void TGWin32::SetWindowBackground(Window_t id, ULong_t color)
4758 {
4759  if (!id) return;
4760 
4761  GdkColor back;
4762  back.pixel = color;
4763  back.red = GetRValue(color);
4764  back.green = GetGValue(color);
4765  back.blue = GetBValue(color);
4766 
4767  gdk_window_set_background((GdkWindow *) id, &back);
4768 }
4769 
4770 ////////////////////////////////////////////////////////////////////////////////
4771 /// Set pixmap as window background.
4772 
4773 void TGWin32::SetWindowBackgroundPixmap(Window_t id, Pixmap_t pxm)
4774 {
4775  if (!id) return;
4776 
4777  gdk_window_set_back_pixmap((GdkWindow *) id, (GdkPixmap *) pxm, 0);
4778 }
4779 
4780 ////////////////////////////////////////////////////////////////////////////////
4781 /// Return handle to newly created gdk window.
4782 
4783 Window_t TGWin32::CreateWindow(Window_t parent, Int_t x, Int_t y,
4784  UInt_t w, UInt_t h, UInt_t border,
4785  Int_t depth, UInt_t clss,
4786  void *visual, SetWindowAttributes_t * attr,
4787  UInt_t wtype)
4788 {
4789  GdkWindowAttr xattr;
4790  GdkWindow *newWin;
4791  GdkColor background_color;
4792  ULong_t xmask = 0;
4793 
4794  if (attr) {
4795  MapSetWindowAttributes(attr, xmask, xattr);
4796  xattr.window_type = GDK_WINDOW_CHILD;
4797  if (wtype & kMainFrame) {
4798  xattr.window_type = GDK_WINDOW_TOPLEVEL;
4799  }
4800  if (wtype & kTransientFrame) {
4801  xattr.window_type = GDK_WINDOW_DIALOG;
4802  }
4803  if (wtype & kTempFrame) {
4804  xattr.window_type = GDK_WINDOW_TEMP;
4805  }
4806  newWin = gdk_window_new((GdkWindow *) parent, &xattr, xmask);
4807  } else {
4808  xattr.width = w;
4809  xattr.height = h;
4810  xattr.wclass = GDK_INPUT_OUTPUT;
4811  xattr.event_mask = 0L; //GDK_ALL_EVENTS_MASK;
4812  xattr.event_mask |= GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK |
4813  GDK_PROPERTY_CHANGE_MASK;
4814 // GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK;
4815  if (x >= 0) {
4816  xattr.x = x;
4817  } else {
4818  xattr.x = -1.0 * x;
4819  }
4820  if (y >= 0) {
4821  xattr.y = y;
4822  } else {
4823  xattr.y = -1.0 * y;
4824  }
4825  xattr.colormap = gdk_colormap_get_system();
4826  xattr.cursor = NULL;
4827  xattr.override_redirect = TRUE;
4828  if ((xattr.y > 0) && (xattr.x > 0)) {
4829  xmask = GDK_WA_X | GDK_WA_Y | GDK_WA_COLORMAP |
4830  GDK_WA_WMCLASS | GDK_WA_NOREDIR;
4831  } else {
4832  xmask = GDK_WA_COLORMAP | GDK_WA_WMCLASS | GDK_WA_NOREDIR;
4833  }
4834  if (visual != NULL) {
4835  xattr.visual = (GdkVisual *) visual;
4836  xmask |= GDK_WA_VISUAL;
4837  } else {
4838  xattr.visual = gdk_visual_get_system();
4839  xmask |= GDK_WA_VISUAL;
4840  }
4841  xattr.window_type = GDK_WINDOW_CHILD;
4842  if (wtype & kMainFrame) {
4843  xattr.window_type = GDK_WINDOW_TOPLEVEL;
4844  }
4845  if (wtype & kTransientFrame) {
4846  xattr.window_type = GDK_WINDOW_DIALOG;
4847  }
4848  if (wtype & kTempFrame) {
4849  xattr.window_type = GDK_WINDOW_TEMP;
4850  }
4851  newWin = gdk_window_new((GdkWindow *) parent, &xattr, xmask);
4852  gdk_window_set_events(newWin, (GdkEventMask) 0L);
4853  }
4854  if (border > 0) {
4855  gdk_window_set_decorations(newWin,
4856  (GdkWMDecoration) GDK_DECOR_BORDER);
4857  }
4858  if (attr) {
4859  if ((attr->fMask & kWABackPixmap)) {
4860  if (attr->fBackgroundPixmap == kNone) {
4861  gdk_window_set_back_pixmap(newWin, (GdkPixmap *) GDK_NONE, 0);
4862  } else if (attr->fBackgroundPixmap == kParentRelative) {
4863  gdk_window_set_back_pixmap(newWin, (GdkPixmap *) GDK_NONE, 1);
4864  } else {
4865  gdk_window_set_back_pixmap(newWin,
4866  (GdkPixmap *) attr->
4867  fBackgroundPixmap, 0);
4868  }
4869  }
4870  if ((attr->fMask & kWABackPixel)) {
4871  background_color.pixel = attr->fBackgroundPixel;
4872  background_color.red = GetRValue(attr->fBackgroundPixel);
4873  background_color.green = GetGValue(attr->fBackgroundPixel);
4874  background_color.blue = GetBValue(attr->fBackgroundPixel);
4875  gdk_window_set_background(newWin, &background_color);
4876  }
4877  }
4878  if (!fUseSysPointers) {
4879  ::SetClassLong((HWND)GDK_DRAWABLE_XID(newWin), GCL_HCURSOR,
4880  (LONG)GDK_CURSOR_XID(fCursors[kPointer]));
4881  }
4882  return (Window_t) newWin;
4883 }
4884 
4885 ////////////////////////////////////////////////////////////////////////////////
4886 /// Map event mask to or from gdk.
4887 
4888 void TGWin32::MapEventMask(UInt_t & emask, UInt_t & xemask, Bool_t tox)
4889 {
4890  if (tox) {
4891  Long_t lxemask = 0L;
4892  if ((emask & kKeyPressMask)) {
4893  lxemask |= GDK_KEY_PRESS_MASK;
4894  }
4895  if ((emask & kKeyReleaseMask)) {
4896  lxemask |= GDK_KEY_RELEASE_MASK;
4897  }
4898  if ((emask & kButtonPressMask)) {
4899  lxemask |= GDK_BUTTON_PRESS_MASK;
4900  }
4901  if ((emask & kButtonReleaseMask)) {
4902  lxemask |= GDK_BUTTON_RELEASE_MASK;
4903  }
4904  if ((emask & kPointerMotionMask)) {
4905  lxemask |= GDK_POINTER_MOTION_MASK;
4906  }
4907  if ((emask & kButtonMotionMask)) {
4908  lxemask |= GDK_BUTTON_MOTION_MASK;
4909  }
4910  if ((emask & kExposureMask)) {
4911  lxemask |= GDK_EXPOSURE_MASK;
4912  }
4913  if ((emask & kStructureNotifyMask)) {
4914  lxemask |= GDK_STRUCTURE_MASK;
4915  }
4916  if ((emask & kEnterWindowMask)) {
4917  lxemask |= GDK_ENTER_NOTIFY_MASK;
4918  }
4919  if ((emask & kLeaveWindowMask)) {
4920  lxemask |= GDK_LEAVE_NOTIFY_MASK;
4921  }
4922  if ((emask & kFocusChangeMask)) {
4923  lxemask |= GDK_FOCUS_CHANGE_MASK;
4924  }
4925  xemask = (UInt_t) lxemask;
4926  } else {
4927  emask = 0;
4928  if ((xemask & GDK_KEY_PRESS_MASK)) {
4929  emask |= kKeyPressMask;
4930  }
4931  if ((xemask & GDK_KEY_RELEASE_MASK)) {
4932  emask |= kKeyReleaseMask;
4933  }
4934  if ((xemask & GDK_BUTTON_PRESS_MASK)) {
4935  emask |= kButtonPressMask;
4936  }
4937  if ((xemask & GDK_BUTTON_RELEASE_MASK)) {
4938  emask |= kButtonReleaseMask;
4939  }
4940  if ((xemask & GDK_POINTER_MOTION_MASK)) {
4941  emask |= kPointerMotionMask;
4942  }
4943  if ((xemask & GDK_BUTTON_MOTION_MASK)) {
4944  emask |= kButtonMotionMask;
4945  }
4946  if ((xemask & GDK_EXPOSURE_MASK)) {
4947  emask |= kExposureMask;
4948  }
4949  if ((xemask & GDK_STRUCTURE_MASK)) {
4950  emask |= kStructureNotifyMask;
4951  }
4952  if ((xemask & GDK_ENTER_NOTIFY_MASK)) {
4953  emask |= kEnterWindowMask;
4954  }
4955  if ((xemask & GDK_LEAVE_NOTIFY_MASK)) {
4956  emask |= kLeaveWindowMask;
4957  }
4958  if ((xemask & GDK_FOCUS_CHANGE_MASK)) {
4959  emask |= kFocusChangeMask;
4960  }
4961  }
4962 }
4963 
4964 ////////////////////////////////////////////////////////////////////////////////
4965 /// Map a SetWindowAttributes_t to a GdkWindowAttr structure.
4966 
4967 void TGWin32::MapSetWindowAttributes(SetWindowAttributes_t * attr,
4968  ULong_t & xmask,
4969  GdkWindowAttr & xattr)
4970 {
4971  Mask_t mask = attr->fMask;
4972  xmask = 0;
4973 
4974  if ((mask & kWAOverrideRedirect)) {
4975  xmask |= GDK_WA_NOREDIR;
4976  xattr.override_redirect = attr->fOverrideRedirect;
4977  }
4978  if ((mask & kWAEventMask)) {
4979  UInt_t xmsk, msk = (UInt_t) attr->fEventMask;
4980  MapEventMask(msk, xmsk, kTRUE);
4981  xattr.event_mask = xmsk;
4982  }
4983  if ((mask & kWAColormap)) {
4984  xmask |= GDK_WA_COLORMAP;
4985  xattr.colormap = (GdkColormap *) attr->fColormap;
4986  }
4987  if ((mask & kWACursor)) {
4988  xmask |= GDK_WA_CURSOR;
4989  if (attr->fCursor != kNone) {
4990  xattr.cursor = (GdkCursor *) attr->fCursor;
4991  }
4992  }
4993  xattr.wclass = GDK_INPUT_OUTPUT;
4994 }
4995 
4996 ////////////////////////////////////////////////////////////////////////////////
4997 /// Map a GCValues_t to a XCGValues structure if tox is true. Map
4998 /// the other way in case tox is false.
4999 
5000 void TGWin32::MapGCValues(GCValues_t & gval,
5001  ULong_t & xmask, GdkGCValues & xgval, Bool_t tox)
5002 {
5003  if (tox) {
5004  // map GCValues_t to XGCValues
5005  Mask_t mask = gval.fMask;
5006  xmask = 0;
5007 
5008  if ((mask & kGCFunction)) {
5009  xmask |= GDK_GC_FUNCTION;
5010  switch (gval.fFunction) {
5011  case kGXclear:
5012  xgval.function = GDK_CLEAR;
5013  break;
5014  case kGXand:
5015  xgval.function = GDK_AND;
5016  break;
5017  case kGXandReverse:
5018  xgval.function = GDK_AND_REVERSE;
5019  break;
5020  case kGXcopy:
5021  xgval.function = GDK_COPY;
5022  break;
5023  case kGXandInverted:
5024  xgval.function = GDK_AND_INVERT;
5025  break;
5026  case kGXnoop:
5027  xgval.function = GDK_NOOP;
5028  break;
5029  case kGXxor:
5030  xgval.function = GDK_XOR;
5031  break;
5032  case kGXor:
5033  xgval.function = GDK_OR;
5034  break;
5035  case kGXequiv:
5036  xgval.function = GDK_EQUIV;
5037  break;
5038  case kGXinvert:
5039  xgval.function = GDK_INVERT;
5040  break;
5041  case kGXorReverse:
5042  xgval.function = GDK_OR_REVERSE;
5043  break;
5044  case kGXcopyInverted:
5045  xgval.function = GDK_COPY_INVERT;
5046  break;
5047  case kGXorInverted:
5048  xgval.function = GDK_OR_INVERT;
5049  break;
5050  case kGXnand:
5051  xgval.function = GDK_NAND;
5052  break;
5053  case kGXset:
5054  xgval.function = GDK_SET;
5055  break;
5056  }
5057  }
5058  if (mask & kGCSubwindowMode) {
5059  xmask |= GDK_GC_SUBWINDOW;
5060  if (gval.fSubwindowMode == kIncludeInferiors) {
5061  xgval.subwindow_mode = GDK_INCLUDE_INFERIORS;
5062  } else {
5063  xgval.subwindow_mode = GDK_CLIP_BY_CHILDREN;
5064  }
5065  }
5066  if (mask & kGCForeground) {
5067  xmask |= GDK_GC_FOREGROUND;
5068  xgval.foreground.pixel = gval.fForeground;
5069  xgval.foreground.red = GetRValue(gval.fForeground);
5070  xgval.foreground.green = GetGValue(gval.fForeground);
5071  xgval.foreground.blue = GetBValue(gval.fForeground);
5072  }
5073  if (mask & kGCBackground) {
5074  xmask |= GDK_GC_BACKGROUND;
5075  xgval.background.pixel = gval.fBackground;
5076  xgval.background.red = GetRValue(gval.fBackground);
5077  xgval.background.green = GetGValue(gval.fBackground);
5078  xgval.background.blue = GetBValue(gval.fBackground);
5079  }
5080  if (mask & kGCLineWidth) {
5081  xmask |= GDK_GC_LINE_WIDTH;
5082  xgval.line_width = gval.fLineWidth;
5083  }
5084  if (mask & kGCLineStyle) {
5085  xmask |= GDK_GC_LINE_STYLE;
5086  xgval.line_style = (GdkLineStyle) gval.fLineStyle; // ident mapping
5087  }
5088  if (mask & kGCCapStyle) {
5089  xmask |= GDK_GC_CAP_STYLE;
5090  xgval.cap_style = (GdkCapStyle) gval.fCapStyle; // ident mapping
5091  }
5092  if (mask & kGCJoinStyle) {
5093  xmask |= GDK_GC_JOIN_STYLE;
5094  xgval.join_style = (GdkJoinStyle) gval.fJoinStyle; // ident mapping
5095  }
5096  if ((mask & kGCFillStyle)) {
5097  xmask |= GDK_GC_FILL;
5098  xgval.fill = (GdkFill) gval.fFillStyle; // ident mapping
5099  }
5100  if ((mask & kGCTile)) {
5101  xmask |= GDK_GC_TILE;
5102  xgval.tile = (GdkPixmap *) gval.fTile;
5103  }
5104  if ((mask & kGCStipple)) {
5105  xmask |= GDK_GC_STIPPLE;
5106  xgval.stipple = (GdkPixmap *) gval.fStipple;
5107  }
5108  if ((mask & kGCTileStipXOrigin)) {
5109  xmask |= GDK_GC_TS_X_ORIGIN;
5110  xgval.ts_x_origin = gval.fTsXOrigin;
5111  }
5112  if ((mask & kGCTileStipYOrigin)) {
5113  xmask |= GDK_GC_TS_Y_ORIGIN;
5114  xgval.ts_y_origin = gval.fTsYOrigin;
5115  }
5116  if ((mask & kGCFont)) {
5117  xmask |= GDK_GC_FONT;
5118  xgval.font = (GdkFont *) gval.fFont;
5119  }
5120  if ((mask & kGCGraphicsExposures)) {
5121  xmask |= GDK_GC_EXPOSURES;
5122  xgval.graphics_exposures = gval.fGraphicsExposures;
5123  }
5124  if ((mask & kGCClipXOrigin)) {
5125  xmask |= GDK_GC_CLIP_X_ORIGIN;
5126  xgval.clip_x_origin = gval.fClipXOrigin;
5127  }
5128  if ((mask & kGCClipYOrigin)) {
5129  xmask |= GDK_GC_CLIP_Y_ORIGIN;
5130  xgval.clip_y_origin = gval.fClipYOrigin;
5131  }
5132  if ((mask & kGCClipMask)) {
5133  xmask |= GDK_GC_CLIP_MASK;
5134  xgval.clip_mask = (GdkPixmap *) gval.fClipMask;
5135  }
5136  } else {
5137  // map XValues to GCValues_t
5138  Mask_t mask = 0;
5139 
5140  if ((xmask & GDK_GC_FUNCTION)) {
5141  mask |= kGCFunction;
5142  gval.fFunction = (EGraphicsFunction) xgval.function; // ident mapping
5143  switch (xgval.function) {
5144  case GDK_CLEAR:
5145  gval.fFunction = kGXclear;
5146  break;
5147  case GDK_AND:
5148  gval.fFunction = kGXand;
5149  break;
5150  case GDK_AND_REVERSE:
5151  gval.fFunction = kGXandReverse;
5152  break;
5153  case GDK_COPY:
5154  gval.fFunction = kGXcopy;
5155  break;
5156  case GDK_AND_INVERT:
5157  gval.fFunction = kGXandInverted;
5158  break;
5159  case GDK_NOOP:
5160  gval.fFunction = kGXnoop;
5161  break;
5162  case GDK_XOR:
5163  gval.fFunction = kGXxor;
5164  break;
5165  case GDK_OR:
5166  gval.fFunction = kGXor;
5167  break;
5168  case GDK_EQUIV:
5169  gval.fFunction = kGXequiv;
5170  break;
5171  case GDK_INVERT:
5172  gval.fFunction = kGXinvert;
5173  break;
5174  case GDK_OR_REVERSE:
5175  gval.fFunction = kGXorReverse;
5176  break;
5177  case GDK_COPY_INVERT:
5178  gval.fFunction = kGXcopyInverted;
5179  break;
5180  case GDK_OR_INVERT:
5181  gval.fFunction = kGXorInverted;
5182  break;
5183  case GDK_NAND:
5184  gval.fFunction = kGXnand;
5185  break;
5186  case GDK_SET:
5187  gval.fFunction = kGXset;
5188  break;
5189  }
5190  }
5191  if (xmask & GDK_GC_SUBWINDOW) {
5192  mask |= kGCSubwindowMode;
5193  if (xgval.subwindow_mode == GDK_INCLUDE_INFERIORS)
5194  gval.fSubwindowMode = kIncludeInferiors;
5195  else
5196  gval.fSubwindowMode = kClipByChildren;
5197  }
5198  if ((xmask & GDK_GC_FOREGROUND)) {
5199  mask |= kGCForeground;
5200  gval.fForeground = xgval.foreground.pixel;
5201  }
5202  if ((xmask & GDK_GC_BACKGROUND)) {
5203  mask |= kGCBackground;
5204  gval.fBackground = xgval.background.pixel;
5205  }
5206  if ((xmask & GDK_GC_LINE_WIDTH)) {
5207  mask |= kGCLineWidth;
5208  gval.fLineWidth = xgval.line_width;
5209  }
5210  if ((xmask & GDK_GC_LINE_STYLE)) {
5211  mask |= kGCLineStyle;
5212  gval.fLineStyle = xgval.line_style; // ident mapping
5213  }
5214  if ((xmask & GDK_GC_CAP_STYLE)) {
5215  mask |= kGCCapStyle;
5216  gval.fCapStyle = xgval.cap_style; // ident mapping
5217  }
5218  if ((xmask & GDK_GC_JOIN_STYLE)) {
5219  mask |= kGCJoinStyle;
5220  gval.fJoinStyle = xgval.join_style; // ident mapping
5221  }
5222  if ((xmask & GDK_GC_FILL)) {
5223  mask |= kGCFillStyle;
5224  gval.fFillStyle = xgval.fill; // ident mapping
5225  }
5226  if ((xmask & GDK_GC_TILE)) {
5227  mask |= kGCTile;
5228  gval.fTile = (Pixmap_t) xgval.tile;
5229  }
5230  if ((xmask & GDK_GC_STIPPLE)) {
5231  mask |= kGCStipple;
5232  gval.fStipple = (Pixmap_t) xgval.stipple;
5233  }
5234  if ((xmask & GDK_GC_TS_X_ORIGIN)) {
5235  mask |= kGCTileStipXOrigin;
5236  gval.fTsXOrigin = xgval.ts_x_origin;
5237  }
5238  if ((xmask & GDK_GC_TS_Y_ORIGIN)) {
5239  mask |= kGCTileStipYOrigin;
5240  gval.fTsYOrigin = xgval.ts_y_origin;
5241  }
5242  if ((xmask & GDK_GC_FONT)) {
5243  mask |= kGCFont;
5244  gval.fFont = (FontH_t) xgval.font;
5245  }
5246  if ((xmask & GDK_GC_EXPOSURES)) {
5247  mask |= kGCGraphicsExposures;
5248  gval.fGraphicsExposures = (Bool_t) xgval.graphics_exposures;
5249  }
5250  if ((xmask & GDK_GC_CLIP_X_ORIGIN)) {
5251  mask |= kGCClipXOrigin;
5252  gval.fClipXOrigin = xgval.clip_x_origin;
5253  }
5254  if ((xmask & GDK_GC_CLIP_Y_ORIGIN)) {
5255  mask |= kGCClipYOrigin;
5256  gval.fClipYOrigin = xgval.clip_y_origin;
5257  }
5258  if ((xmask & GDK_GC_CLIP_MASK)) {
5259  mask |= kGCClipMask;
5260  gval.fClipMask = (Pixmap_t) xgval.clip_mask;
5261  }
5262  gval.fMask = mask;
5263  }
5264 }
5265 
5266 ////////////////////////////////////////////////////////////////////////////////
5267 /// Get window attributes and return filled in attributes structure.
5268 
5269 void TGWin32::GetWindowAttributes(Window_t id, WindowAttributes_t & attr)
5270 {
5271  if (!id) return;
5272 
5273  RECT rcClient, rcWind;
5274  ::GetClientRect((HWND)GDK_DRAWABLE_XID((GdkWindow *) id), &rcClient);
5275  ::GetWindowRect((HWND)GDK_DRAWABLE_XID((GdkWindow *) id), &rcWind);
5276 
5277  gdk_window_get_geometry((GdkWindow *) id, &attr.fX, &attr.fY,
5278  &attr.fWidth, &attr.fHeight, &attr.fDepth);
5279  attr.fX = ((rcWind.right - rcWind.left) - rcClient.right) / 2;
5280  attr.fY = ((rcWind.bottom - rcWind.top) - rcClient.bottom) - attr.fX;
5281 
5282  attr.fRoot = (Window_t) GDK_ROOT_PARENT();
5283  attr.fColormap = (Colormap_t) gdk_window_get_colormap((GdkWindow *) id);
5284  attr.fBorderWidth = 0;
5285  attr.fVisual = gdk_window_get_visual((GdkWindow *) id);
5286  attr.fClass = kInputOutput;
5287  attr.fBackingStore = kNotUseful;
5288  attr.fSaveUnder = kFALSE;
5289  attr.fMapInstalled = kTRUE;
5290  attr.fOverrideRedirect = kFALSE; // boolean value for override-redirect
5291 
5292  if (!gdk_window_is_visible((GdkWindow *) id)) {
5293  attr.fMapState = kIsUnmapped;
5294  } else if (!gdk_window_is_viewable((GdkWindow *) id)) {
5295  attr.fMapState = kIsUnviewable;
5296  } else {
5297  attr.fMapState = kIsViewable;
5298  }
5299 
5300  UInt_t tmp_mask = (UInt_t)gdk_window_get_events((GdkWindow *) id);
5301  UInt_t evmask;
5302  MapEventMask(evmask, tmp_mask, kFALSE);
5303 
5304  attr.fYourEventMask = evmask;
5305 }
5306 
5307 ////////////////////////////////////////////////////////////////////////////////
5308 ///
5309 
5310 Display_t TGWin32::GetDisplay() const
5311 {
5312  return 0;
5313 }
5314 
5315 ////////////////////////////////////////////////////////////////////////////////
5316 /// Get maximum number of planes.
5317 
5318 Int_t TGWin32::GetDepth() const
5319 {
5320  return gdk_visual_get_best_depth();
5321 }
5322 
5323 ////////////////////////////////////////////////////////////////////////////////
5324 /// Return atom handle for atom_name. If it does not exist
5325 /// create it if only_if_exist is false. Atoms are used to communicate
5326 /// between different programs (i.e. window manager) via the X server.
5327 
5328 Atom_t TGWin32::InternAtom(const char *atom_name, Bool_t only_if_exist)
5329 {
5330  GdkAtom a = gdk_atom_intern((const gchar *) atom_name, only_if_exist);
5331 
5332  if (a == None) return kNone;
5333  return (Atom_t) a;
5334 }
5335 
5336 ////////////////////////////////////////////////////////////////////////////////
5337 /// Return handle to the default root window created when calling
5338 /// XOpenDisplay().
5339 
5340 Window_t TGWin32::GetDefaultRootWindow() const
5341 {
5342  return (Window_t) GDK_ROOT_PARENT();
5343 }
5344 
5345 ////////////////////////////////////////////////////////////////////////////////
5346 /// Return the parent of the window.
5347 
5348 Window_t TGWin32::GetParent(Window_t id) const
5349 {
5350  if (!id) return (Window_t)0;
5351 
5352  return (Window_t)gdk_window_get_parent((GdkWindow *) id);
5353 }
5354 
5355 ////////////////////////////////////////////////////////////////////////////////
5356 /// Load font and query font. If font is not found 0 is returned,
5357 /// otherwise an opaque pointer to the FontStruct_t.
5358 /// Free the loaded font using DeleteFont().
5359 
5360 FontStruct_t TGWin32::LoadQueryFont(const char *font_name)
5361 {
5362  char family[100], weight[32], slant[32], fontname[256];
5363  Int_t n1, pixel, numfields;
5364 
5365  numfields = sscanf(font_name, "%s -%d%n", family, &pixel, &n1);
5366  if (numfields == 2) {
5367  sprintf(weight,"medium");
5368  if (strstr(font_name, "bold"))
5369  sprintf(weight,"bold");
5370  sprintf(slant,"r");
5371  if (strstr(font_name, "italic"))
5372  sprintf(slant,"i");
5373  sprintf(fontname, "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-iso8859-1",
5374  family, weight, slant, pixel);
5375  }
5376  else
5377  sprintf(fontname, "%s", font_name);
5378  return (FontStruct_t) gdk_font_load(fontname);
5379 }
5380 
5381 ////////////////////////////////////////////////////////////////////////////////
5382 /// Return handle to font described by font structure.
5383 
5384 FontH_t TGWin32::GetFontHandle(FontStruct_t fs)
5385 {
5386  if (fs) {
5387  return (FontH_t)gdk_font_ref((GdkFont *) fs);
5388  }
5389  return 0;
5390 }
5391 
5392 ////////////////////////////////////////////////////////////////////////////////
5393 /// Explicitely delete font structure obtained with LoadQueryFont().
5394 
5395 void TGWin32::DeleteFont(FontStruct_t fs)
5396 {
5397  gdk_font_unref((GdkFont *) fs);
5398 }
5399 
5400 ////////////////////////////////////////////////////////////////////////////////
5401 /// Create a graphics context using the values set in gval (but only for
5402 /// those entries that are in the mask).
5403 
5404 GContext_t TGWin32::CreateGC(Drawable_t id, GCValues_t *gval)
5405 {
5406  if (!id) return (GContext_t)0;
5407 
5408  GdkGCValues xgval;
5409  ULong_t xmask = 0;
5410 
5411  if (gval) MapGCValues(*gval, xmask, xgval, kTRUE);
5412 
5413  xgval.subwindow_mode = GDK_CLIP_BY_CHILDREN; // GDK_INCLUDE_INFERIORS;
5414 
5415  GdkGC *gc = gdk_gc_new_with_values((GdkDrawable *) id,
5416  &xgval, (GdkGCValuesMask)xmask);
5417  return (GContext_t) gc;
5418 }
5419 
5420 ////////////////////////////////////////////////////////////////////////////////
5421 /// Change entries in an existing graphics context, gc, by values from gval.
5422 
5423 void TGWin32::ChangeGC(GContext_t gc, GCValues_t * gval)
5424 {
5425  GdkGCValues xgval;
5426  ULong_t xmask = 0;
5427  Mask_t mask = 0;
5428 
5429  if (gval) {
5430  mask = gval->fMask;
5431  MapGCValues(*gval, xmask, xgval, kTRUE);
5432  }
5433  if (mask & kGCForeground) {
5434  gdk_gc_set_foreground((GdkGC *) gc, &xgval.foreground);
5435  }
5436  if (mask & kGCBackground) {
5437  gdk_gc_set_background((GdkGC *) gc, &xgval.background);
5438  }
5439  if (mask & kGCFont) {
5440  gdk_gc_set_font((GdkGC *) gc, xgval.font);
5441  }
5442  if (mask & kGCFunction) {
5443  gdk_gc_set_function((GdkGC *) gc, xgval.function);
5444  }
5445  if (mask & kGCFillStyle) {
5446  gdk_gc_set_fill((GdkGC *) gc, xgval.fill);
5447  }
5448  if (mask & kGCTile) {
5449  gdk_gc_set_tile((GdkGC *) gc, xgval.tile);
5450  }
5451  if (mask & kGCStipple) {
5452  gdk_gc_set_stipple((GdkGC *) gc, xgval.stipple);
5453  }
5454  if ((mask & kGCTileStipXOrigin) || (mask & kGCTileStipYOrigin)) {
5455  gdk_gc_set_ts_origin((GdkGC *) gc, xgval.ts_x_origin,
5456  xgval.ts_y_origin);
5457  }
5458  if ((mask & kGCClipXOrigin) || (mask & kGCClipYOrigin)) {
5459  gdk_gc_set_clip_origin((GdkGC *) gc, xgval.clip_x_origin,
5460  xgval.clip_y_origin);
5461  }
5462  if (mask & kGCClipMask) {
5463  gdk_gc_set_clip_mask((GdkGC *) gc, xgval.clip_mask);
5464  }
5465  if (mask & kGCGraphicsExposures) {
5466  gdk_gc_set_exposures((GdkGC *) gc, xgval.graphics_exposures);
5467  }
5468  if (mask & kGCLineWidth) {
5469  gdk_gc_set_values((GdkGC *) gc, &xgval, GDK_GC_LINE_WIDTH);
5470  }
5471  if (mask & kGCLineStyle) {
5472  gdk_gc_set_values((GdkGC *) gc, &xgval, GDK_GC_LINE_STYLE);
5473  }
5474  if (mask & kGCCapStyle) {
5475  gdk_gc_set_values((GdkGC *) gc, &xgval, GDK_GC_CAP_STYLE);
5476  }
5477  if (mask & kGCJoinStyle) {
5478  gdk_gc_set_values((GdkGC *) gc, &xgval, GDK_GC_JOIN_STYLE);
5479  }
5480  if (mask & kGCSubwindowMode) {
5481  gdk_gc_set_subwindow((GdkGC *) gc, xgval.subwindow_mode);
5482  }
5483 }
5484 
5485 ////////////////////////////////////////////////////////////////////////////////
5486 /// Copies graphics context from org to dest. Only the values specified
5487 /// in mask are copied. Both org and dest must exist.
5488 
5489 void TGWin32::CopyGC(GContext_t org, GContext_t dest, Mask_t mask)
5490 {
5491  GCValues_t gval;
5492  GdkGCValues xgval;
5493  ULong_t xmask;
5494 
5495  if (!mask) {
5496  // in this case copy all fields
5497  mask = (Mask_t) - 1;
5498  }
5499 
5500  gval.fMask = mask; // only set fMask used to convert to xmask
5501  MapGCValues(gval, xmask, xgval, kTRUE);
5502 
5503  gdk_gc_copy((GdkGC *) dest, (GdkGC *) org);
5504 }
5505 
5506 ////////////////////////////////////////////////////////////////////////////////
5507 /// Explicitely delete a graphics context.
5508 
5509 void TGWin32::DeleteGC(GContext_t gc)
5510 {
5511  gdk_gc_unref((GdkGC *) gc);
5512 }
5513 
5514 ////////////////////////////////////////////////////////////////////////////////
5515 /// Create cursor handle (just return cursor from cursor pool fCursors).
5516 
5517 Cursor_t TGWin32::CreateCursor(ECursor cursor)
5518 {
5519  return (Cursor_t) fCursors[cursor];
5520 }
5521 
5522 ////////////////////////////////////////////////////////////////////////////////
5523 /// Creates a pixmap of the width and height you specified
5524 /// and returns a pixmap ID that identifies it.
5525 
5526 Pixmap_t TGWin32::CreatePixmap(Drawable_t id, UInt_t w, UInt_t h)
5527 {
5528  GdkWindow *wid = (GdkWindow *)id;
5529  if (!id) wid = GDK_ROOT_PARENT();
5530 
5531  return (Pixmap_t) gdk_pixmap_new(wid, w, h, gdk_visual_get_best_depth());
5532 }
5533 
5534 ////////////////////////////////////////////////////////////////////////////////
5535 /// Create a pixmap from bitmap data. Ones will get foreground color and
5536 /// zeroes background color.
5537 
5538 Pixmap_t TGWin32::CreatePixmap(Drawable_t id, const char *bitmap,
5539  UInt_t width, UInt_t height,
5540  ULong_t forecolor, ULong_t backcolor,
5541  Int_t depth)
5542 {
5543  GdkColor fore, back;
5544  fore.pixel = forecolor;
5545  fore.red = GetRValue(forecolor);
5546  fore.green = GetGValue(forecolor);
5547  fore.blue = GetBValue(forecolor);
5548 
5549  back.pixel = backcolor;
5550  back.red = GetRValue(backcolor);
5551  back.green = GetGValue(backcolor);
5552  back.blue = GetBValue(backcolor);
5553 
5554  GdkWindow *wid = (GdkWindow *)id;
5555  if (!id) wid = GDK_ROOT_PARENT();
5556 
5557  return (Pixmap_t) gdk_pixmap_create_from_data(wid, (char *) bitmap, width,
5558  height, depth, &fore, &back);
5559 }
5560 
5561 ////////////////////////////////////////////////////////////////////////////////
5562 /// Create a bitmap (i.e. pixmap with depth 1) from the bitmap data.
5563 
5564 Pixmap_t TGWin32::CreateBitmap(Drawable_t id, const char *bitmap,
5565  UInt_t width, UInt_t height)
5566 {
5567  GdkWindow *wid = (GdkWindow *)id;
5568  if (!id) wid = GDK_ROOT_PARENT();
5569 
5570  Pixmap_t ret = (Pixmap_t) gdk_bitmap_create_from_data(wid,
5571  (char *)bitmap, width, height);
5572  return ret;
5573 }
5574 
5575 ////////////////////////////////////////////////////////////////////////////////
5576 /// Explicitely delete pixmap resource.
5577 
5578 void TGWin32::DeletePixmap(Pixmap_t pmap)
5579 {
5580  gdk_pixmap_unref((GdkPixmap *) pmap);
5581 }
5582 
5583 ////////////////////////////////////////////////////////////////////////////////
5584 /// Create a picture pixmap from data on file. The picture attributes
5585 /// are used for input and output. Returns kTRUE in case of success,
5586 /// kFALSE otherwise. If mask does not exist it is set to kNone.
5587 
5588 Bool_t TGWin32::CreatePictureFromFile(Drawable_t id, const char *filename,
5589  Pixmap_t & pict,
5590  Pixmap_t & pict_mask,
5591  PictureAttributes_t & attr)
5592 {
5593  GdkBitmap *gdk_pixmap_mask;
5594  if (strstr(filename, ".xpm") || strstr(filename, ".XPM")) {
5595  GdkWindow *wid = (GdkWindow *)id;
5596  if (!id) wid = GDK_ROOT_PARENT();
5597 
5598  pict = (Pixmap_t) gdk_pixmap_create_from_xpm(wid, &gdk_pixmap_mask, 0,
5599  filename);
5600  pict_mask = (Pixmap_t) gdk_pixmap_mask;
5601  } else if (strstr(filename, ".gif") || strstr(filename, ".GIF")) {
5602  pict = ReadGIF(0, 0, filename, id);
5603  pict_mask = kNone;
5604  }
5605 
5606  gdk_drawable_get_size((GdkPixmap *) pict, (int *) &attr.fWidth,
5607  (int *) &attr.fHeight);
5608  if (pict) {
5609  return kTRUE;
5610  }
5611  if (pict_mask) {
5612  pict_mask = kNone;
5613  }
5614  return kFALSE;
5615 }
5616 
5617 ////////////////////////////////////////////////////////////////////////////////
5618 /// Create a pixture pixmap from data. The picture attributes
5619 /// are used for input and output. Returns kTRUE in case of success,
5620 /// kFALSE otherwise. If mask does not exist it is set to kNone.
5621 
5622 Bool_t TGWin32::CreatePictureFromData(Drawable_t id, char **data,
5623  Pixmap_t & pict,
5624  Pixmap_t & pict_mask,
5625  PictureAttributes_t & attr)
5626 {
5627  GdkBitmap *gdk_pixmap_mask;
5628  GdkWindow *wid = (GdkWindow *)id;
5629  if (!id) wid = GDK_ROOT_PARENT();
5630 
5631  pict = (Pixmap_t) gdk_pixmap_create_from_xpm_d(wid, &gdk_pixmap_mask, 0,
5632  data);
5633  pict_mask = (Pixmap_t) gdk_pixmap_mask;
5634 
5635  if (pict) {
5636  return kTRUE;
5637  }
5638  if (pict_mask) {
5639  pict_mask = kNone;
5640  }
5641  return kFALSE;
5642 }
5643 
5644 ////////////////////////////////////////////////////////////////////////////////
5645 /// Read picture data from file and store in ret_data. Returns kTRUE in
5646 /// case of success, kFALSE otherwise.
5647 
5648 Bool_t TGWin32::ReadPictureDataFromFile(const char *filename, char ***ret_data)
5649 {
5650  Bool_t ret = kFALSE;
5651  GdkPixmap *pxm = gdk_pixmap_create_from_xpm(NULL, NULL, NULL, filename);
5652  ret_data = 0;
5653 
5654  if (pxm==NULL) return kFALSE;
5655 
5656  HBITMAP hbm = (HBITMAP)GDK_DRAWABLE_XID(pxm);
5657  BITMAP bitmap;
5658 
5659  ret = ::GetObject(hbm, sizeof(HBITMAP), (LPVOID)&bitmap);
5660  ret_data = (char ***)&bitmap.bmBits;
5661  gdk_pixmap_unref(pxm);
5662  return ret;
5663 }
5664 
5665 ////////////////////////////////////////////////////////////////////////////////
5666 /// Delete picture data created by the function ReadPictureDataFromFile.
5667 
5668 void TGWin32::DeletePictureData(void *data)
5669 {
5670  free(data);
5671 }
5672 
5673 ////////////////////////////////////////////////////////////////////////////////
5674 /// Specify a dash pattertn. Offset defines the phase of the pattern.
5675 /// Each element in the dash_list array specifies the length (in pixels)
5676 /// of a segment of the pattern. N defines the length of the list.
5677 
5678 void TGWin32::SetDashes(GContext_t gc, Int_t offset, const char *dash_list,
5679  Int_t n)
5680 {
5681  int i;
5682  gint8 dashes[32];
5683  for (i = 0; i < n; i++) {
5684  dashes[i] = (gint8) dash_list[i];
5685  }
5686  for (i = n; i < 32; i++) {
5687  dashes[i] = (gint8) 0;
5688  }
5689 
5690  gdk_gc_set_dashes((GdkGC *) gc, offset, dashes, n);
5691 }
5692 
5693 ////////////////////////////////////////////////////////////////////////////////
5694 /// Map a ColorStruct_t to a XColor structure.
5695 
5696 void TGWin32::MapColorStruct(ColorStruct_t * color, GdkColor & xcolor)
5697 {
5698  xcolor.pixel = color->fPixel;
5699  xcolor.red = color->fRed;
5700  xcolor.green = color->fGreen;
5701  xcolor.blue = color->fBlue;
5702 }
5703 
5704 ////////////////////////////////////////////////////////////////////////////////
5705 /// Parse string cname containing color name, like "green" or "#00FF00".
5706 /// It returns a filled in ColorStruct_t. Returns kFALSE in case parsing
5707 /// failed, kTRUE in case of success. On success, the ColorStruct_t
5708 /// fRed, fGreen and fBlue fields are all filled in and the mask is set
5709 /// for all three colors, but fPixel is not set.
5710 
5711 Bool_t TGWin32::ParseColor(Colormap_t cmap, const char *cname,
5712  ColorStruct_t & color)
5713 {
5714  GdkColor xc;
5715 
5716  if (gdk_color_parse((char *)cname, &xc)) {
5717  color.fPixel = xc.pixel = RGB(xc.red, xc.green, xc.blue);
5718  color.fRed = xc.red;
5719  color.fGreen = xc.green;
5720  color.fBlue = xc.blue;
5721  return kTRUE;
5722  }
5723  return kFALSE;
5724 }
5725 
5726 ////////////////////////////////////////////////////////////////////////////////
5727 /// Find and allocate a color cell according to the color values specified
5728 /// in the ColorStruct_t. If no cell could be allocated it returns kFALSE,
5729 /// otherwise kTRUE.
5730 
5731 Bool_t TGWin32::AllocColor(Colormap_t cmap, ColorStruct_t & color)
5732 {
5733  int status;
5734  GdkColor xc;
5735 
5736  xc.red = color.fRed;
5737  xc.green = color.fGreen;
5738  xc.blue = color.fBlue;
5739 
5740  status = gdk_colormap_alloc_color((GdkColormap *) cmap, &xc, FALSE, TRUE);
5741  color.fPixel = xc.pixel;
5742 
5743  return kTRUE; // status != 0 ? kTRUE : kFALSE;
5744 }
5745 
5746 ////////////////////////////////////////////////////////////////////////////////
5747 /// Fill in the primary color components for a specific pixel value.
5748 /// On input fPixel should be set on return the fRed, fGreen and
5749 /// fBlue components will be set.
5750 
5751 void TGWin32::QueryColor(Colormap_t cmap, ColorStruct_t & color)
5752 {
5753  GdkColor xc;
5754  xc.pixel = color.fPixel;
5755 
5756  GdkColorContext *cc = gdk_color_context_new(gdk_visual_get_system(), fColormap);
5757  gdk_color_context_query_color(cc, &xc);
5758  gdk_color_context_free(cc);
5759 
5760  color.fPixel = xc.pixel;
5761  color.fRed = xc.red;
5762  color.fGreen = xc.green;
5763  color.fBlue = xc.blue;
5764 }
5765 
5766 ////////////////////////////////////////////////////////////////////////////////
5767 /// Free color cell with specified pixel value.
5768 
5769 void TGWin32::FreeColor(Colormap_t cmap, ULong_t pixel)
5770 {
5771  // FIXME: to be implemented.
5772 }
5773 
5774 ////////////////////////////////////////////////////////////////////////////////
5775 /// Check if there is for window "id" an event of type "type". If there
5776 /// is fill in the event structure and return true. If no such event
5777 /// return false.
5778 
5779 Bool_t TGWin32::CheckEvent(Window_t id, EGEventType type, Event_t & ev)
5780 {
5781  if (!id) return kFALSE;
5782 
5783  Event_t tev;
5784  GdkEvent xev;
5785 
5786  tev.fType = type;
5787  tev.fWindow = (Window_t) id;
5788  tev.fTime = 0;
5789  tev.fX = tev.fY = 0;
5790  tev.fXRoot = tev.fYRoot = 0;
5791  tev.fCode = 0;
5792  tev.fState = 0;
5793  tev.fWidth = tev.fHeight = 0;
5794  tev.fCount = 0;
5795  tev.fSendEvent = kFALSE;
5796  tev.fHandle = 0;
5797  tev.fFormat = 0;
5798  tev.fUser[0] = tev.fUser[1] = tev.fUser[2] = tev.fUser[3] = tev.fUser[4] = 0L;
5799 
5800  TGWin32MainThread::LockMSG();
5801  MapEvent(tev, xev, kTRUE);
5802  Bool_t r = gdk_check_typed_window_event((GdkWindow *) id, xev.type, &xev);
5803 
5804  if (r) MapEvent(ev, xev, kFALSE);
5805  TGWin32MainThread::UnlockMSG();
5806 
5807  return r ? kTRUE : kFALSE;
5808 }
5809 
5810 ////////////////////////////////////////////////////////////////////////////////
5811 /// Send event ev to window id.
5812 
5813 void TGWin32::SendEvent(Window_t id, Event_t * ev)
5814 {
5815  if (!ev || !id) return;
5816 
5817  TGWin32MainThread::LockMSG();
5818  GdkEvent xev;
5819  MapEvent(*ev, xev, kTRUE);
5820  gdk_event_put(&xev);
5821  TGWin32MainThread::UnlockMSG();
5822 }
5823 
5824 ////////////////////////////////////////////////////////////////////////////////
5825 /// Returns number of pending events.
5826 
5827 Int_t TGWin32::EventsPending()
5828 {
5829  Int_t ret;
5830 
5831  TGWin32MainThread::LockMSG();
5832  ret = (Int_t)gdk_event_queue_find_first();
5833  TGWin32MainThread::UnlockMSG();
5834 
5835  return ret;
5836 }
5837 
5838 ////////////////////////////////////////////////////////////////////////////////
5839 /// Copies first pending event from event queue to Event_t structure
5840 /// and removes event from queue. Not all of the event fields are valid
5841 /// for each event type, except fType and fWindow.
5842 
5843 void TGWin32::NextEvent(Event_t & event)
5844 {
5845  TGWin32MainThread::LockMSG();
5846  GdkEvent *xev = gdk_event_unqueue();
5847 
5848  // fill in Event_t
5849  event.fType = kOtherEvent; // bb add
5850  if (xev == NULL) {
5851  TGWin32MainThread::UnlockMSG();
5852  return;
5853  }
5854  MapEvent(event, *xev, kFALSE);
5855  gdk_event_free (xev);
5856  TGWin32MainThread::UnlockMSG();
5857 }
5858 
5859 ////////////////////////////////////////////////////////////////////////////////
5860 /// Map modifier key state to or from X.
5861 
5862 void TGWin32::MapModifierState(UInt_t & state, UInt_t & xstate, Bool_t tox)
5863 {
5864  if (tox) {
5865  xstate = state;
5866  if (state & kAnyModifier) {
5867  xstate = GDK_MODIFIER_MASK;
5868  }
5869  } else {
5870  state = xstate;
5871  }
5872 }
5873 
5874 static void _set_event_time(GdkEvent &event, UInt_t time)
5875 {
5876  // set gdk event time
5877 
5878  switch (event.type) {
5879  case GDK_MOTION_NOTIFY:
5880  event.motion.time = time;
5881  case GDK_BUTTON_PRESS:
5882  case GDK_2BUTTON_PRESS:
5883  case GDK_3BUTTON_PRESS:
5884  case GDK_BUTTON_RELEASE:
5885  case GDK_SCROLL:
5886  event.button.time = time;
5887  case GDK_KEY_PRESS:
5888  case GDK_KEY_RELEASE:
5889  event.key.time = time;
5890  case GDK_ENTER_NOTIFY:
5891  case GDK_LEAVE_NOTIFY:
5892  event.crossing.time = time;
5893  case GDK_PROPERTY_NOTIFY:
5894  event.property.time = time;
5895  case GDK_SELECTION_CLEAR:
5896  case GDK_SELECTION_REQUEST:
5897  case GDK_SELECTION_NOTIFY:
5898  event.selection.time = time;
5899  case GDK_PROXIMITY_IN:
5900  case GDK_PROXIMITY_OUT:
5901  event.proximity.time = time;
5902  case GDK_DRAG_ENTER:
5903  case GDK_DRAG_LEAVE:
5904  case GDK_DRAG_MOTION:
5905  case GDK_DRAG_STATUS:
5906  case GDK_DROP_START:
5907  case GDK_DROP_FINISHED:
5908  event.dnd.time = time;
5909  default: /* use current time */
5910  break;
5911  }
5912 }
5913 
5914 ////////////////////////////////////////////////////////////////////////////////
5915 /// Map Event_t structure to gdk_event structure. If tox is false
5916 /// map the other way.
5917 
5918 void TGWin32::MapEvent(Event_t & ev, GdkEvent & xev, Bool_t tox)
5919 {
5920  if (tox) {
5921  // map from Event_t to gdk_event
5922  xev.type = GDK_NOTHING;
5923  if (ev.fType == kGKeyPress)
5924  xev.type = GDK_KEY_PRESS;
5925  if (ev.fType == kKeyRelease)
5926  xev.type = GDK_KEY_RELEASE;
5927  if (ev.fType == kButtonPress)
5928  xev.type = GDK_BUTTON_PRESS;
5929  if (ev.fType == kButtonRelease)
5930  xev.type = GDK_BUTTON_RELEASE;
5931  if (ev.fType == kMotionNotify)
5932  xev.type = GDK_MOTION_NOTIFY;
5933  if (ev.fType == kEnterNotify)
5934  xev.type = GDK_ENTER_NOTIFY;
5935  if (ev.fType == kLeaveNotify)
5936  xev.type = GDK_LEAVE_NOTIFY;
5937  if (ev.fType == kExpose)
5938  xev.type = GDK_EXPOSE;
5939  if (ev.fType == kConfigureNotify)
5940  xev.type = GDK_CONFIGURE;
5941  if (ev.fType == kMapNotify)
5942  xev.type = GDK_MAP;
5943  if (ev.fType == kUnmapNotify)
5944  xev.type = GDK_UNMAP;
5945  if (ev.fType == kDestroyNotify)
5946  xev.type = GDK_DESTROY;
5947  if (ev.fType == kClientMessage)
5948  xev.type = GDK_CLIENT_EVENT;
5949  if (ev.fType == kSelectionClear)
5950  xev.type = GDK_SELECTION_CLEAR;
5951  if (ev.fType == kSelectionRequest)
5952  xev.type = GDK_SELECTION_REQUEST;
5953  if (ev.fType == kSelectionNotify)
5954  xev.type = GDK_SELECTION_NOTIFY;
5955 
5956  xev.any.type = xev.type;
5957  xev.any.send_event = ev.fSendEvent;
5958  if (ev.fType == kDestroyNotify) {
5959  xev.any.window = (GdkWindow *) ev.fWindow;
5960  }
5961  if (ev.fType == kFocusIn) {
5962  xev.type = GDK_FOCUS_CHANGE;
5963  xev.focus_change.type = xev.type;
5964  xev.focus_change.window = (GdkWindow *) ev.fWindow;
5965  xev.focus_change.in = TRUE;
5966  }
5967  if (ev.fType == kFocusOut) {
5968  xev.type = GDK_FOCUS_CHANGE;
5969  xev.focus_change.type = xev.type;
5970  xev.focus_change.window = (GdkWindow *) ev.fWindow;
5971  xev.focus_change.in = FALSE;
5972  }
5973  if (ev.fType == kGKeyPress || ev.fType == kKeyRelease) {
5974  xev.key.window = (GdkWindow *) ev.fWindow;
5975  xev.key.type = xev.type;
5976  MapModifierState(ev.fState, xev.key.state, kTRUE); // key mask
5977  xev.key.keyval = ev.fCode; // key code
5978  }
5979  if (ev.fType == kButtonPress || ev.fType == kButtonRelease) {
5980  xev.button.window = (GdkWindow *) ev.fWindow;
5981  xev.button.type = xev.type;
5982  xev.button.x = ev.fX;
5983  xev.button.y = ev.fY;
5984  xev.button.x_root = ev.fXRoot;
5985  xev.button.y_root = ev.fYRoot;
5986  MapModifierState(ev.fState, xev.button.state, kTRUE); // button mask
5987  xev.button.button = ev.fCode; // button code
5988  }
5989  if (ev.fType == kSelectionNotify) {
5990  xev.selection.window = (GdkWindow *) ev.fUser[0];
5991  xev.selection.requestor = (guint32) ev.fUser[0];
5992  xev.selection.selection = (GdkAtom) ev.fUser[1];
5993  xev.selection.target = (GdkAtom) ev.fUser[2];
5994  xev.selection.property = (GdkAtom) ev.fUser[3];
5995  xev.selection.type = xev.type;
5996  }
5997  if (ev.fType == kClientMessage) {
5998  if ((ev.fFormat == 32) && (ev.fHandle == gWM_DELETE_WINDOW)) {
5999  xev.type = GDK_DELETE;
6000  xev.any.type = xev.type;
6001  xev.any.window = (GdkWindow *) ev.fWindow;
6002  } else {
6003  xev.client.window = (GdkWindow *) ev.fWindow;
6004  xev.client.type = xev.type;
6005  xev.client.message_type = (GdkAtom) ev.fHandle;
6006  xev.client.data_format = ev.fFormat;
6007  xev.client.data.l[0] = ev.fUser[0];
6008  if (sizeof(ev.fUser[0]) > 4) {
6009  SplitLong(ev.fUser[1], xev.client.data.l[1],
6010  xev.client.data.l[3]);
6011  SplitLong(ev.fUser[2], xev.client.data.l[2],
6012  xev.client.data.l[4]);
6013  } else {
6014  xev.client.data.l[1] = ev.fUser[1];
6015  xev.client.data.l[2] = ev.fUser[2];
6016  xev.client.data.l[3] = ev.fUser[3];
6017  xev.client.data.l[4] = ev.fUser[4];
6018  }
6019  }
6020  }
6021  if (ev.fType == kMotionNotify) {
6022  xev.motion.window = (GdkWindow *) ev.fWindow;
6023  xev.motion.type = xev.type;
6024  xev.motion.x = ev.fX;
6025  xev.motion.y = ev.fY;
6026  xev.motion.x_root = ev.fXRoot;
6027  xev.motion.y_root = ev.fYRoot;
6028  }
6029  if ((ev.fType == kEnterNotify) || (ev.fType == kLeaveNotify)) {
6030  xev.crossing.window = (GdkWindow *) ev.fWindow;
6031  xev.crossing.type = xev.type;
6032  xev.crossing.x = ev.fX;
6033  xev.crossing.y = ev.fY;
6034  xev.crossing.x_root = ev.fXRoot;
6035  xev.crossing.y_root = ev.fYRoot;
6036  xev.crossing.mode = (GdkCrossingMode) ev.fCode; // NotifyNormal, NotifyGrab, NotifyUngrab
6037  MapModifierState(ev.fState, xev.crossing.state, kTRUE); // key or button mask
6038  }
6039  if (ev.fType == kExpose) {
6040  xev.expose.window = (GdkWindow *) ev.fWindow;
6041  xev.expose.type = xev.type;
6042  xev.expose.area.x = ev.fX;
6043  xev.expose.area.y = ev.fY;
6044  xev.expose.area.width = ev.fWidth; // width and
6045  xev.expose.area.height = ev.fHeight; // height of exposed area
6046  xev.expose.count = ev.fCount; // number of expose events still to come
6047  }
6048  if (ev.fType == kConfigureNotify) {
6049  xev.configure.window = (GdkWindow *) ev.fWindow;
6050  xev.configure.type = xev.type;
6051  xev.configure.x = ev.fX;
6052  xev.configure.y = ev.fY;
6053  xev.configure.width = ev.fWidth;
6054  xev.configure.height = ev.fHeight;
6055  }
6056  if (ev.fType == kSelectionClear) {
6057  xev.selection.window = (GdkWindow *) ev.fWindow;
6058  xev.selection.type = xev.type;
6059  xev.selection.selection = ev.fUser[0];
6060  }
6061  if (ev.fType == kSelectionRequest) {
6062  xev.selection.window = (GdkWindow *) ev.fUser[0];
6063  xev.selection.type = xev.type;
6064  xev.selection.selection = ev.fUser[1];
6065  xev.selection.target = ev.fUser[2];
6066  xev.selection.property = ev.fUser[3];
6067  }
6068  if ((ev.fType == kMapNotify) || (ev.fType == kUnmapNotify)) {
6069  xev.any.window = (GdkWindow *) ev.fWindow;
6070  }
6071  if (xev.type != GDK_CLIENT_EVENT)
6072  _set_event_time(xev, ev.fTime);
6073  } else {
6074  // map from gdk_event to Event_t
6075  ev.fType = kOtherEvent;
6076  if (xev.type == GDK_KEY_PRESS)
6077  ev.fType = kGKeyPress;
6078  if (xev.type == GDK_KEY_RELEASE)
6079  ev.fType = kKeyRelease;
6080  if (xev.type == GDK_BUTTON_PRESS)
6081  ev.fType = kButtonPress;
6082  if (xev.type == GDK_BUTTON_RELEASE)
6083  ev.fType = kButtonRelease;
6084  if (xev.type == GDK_MOTION_NOTIFY)
6085  ev.fType = kMotionNotify;
6086  if (xev.type == GDK_ENTER_NOTIFY)
6087  ev.fType = kEnterNotify;
6088  if (xev.type == GDK_LEAVE_NOTIFY)
6089  ev.fType = kLeaveNotify;
6090  if (xev.type == GDK_EXPOSE)
6091  ev.fType = kExpose;
6092  if (xev.type == GDK_CONFIGURE)
6093  ev.fType = kConfigureNotify;
6094  if (xev.type == GDK_MAP)
6095  ev.fType = kMapNotify;
6096  if (xev.type == GDK_UNMAP)
6097  ev.fType = kUnmapNotify;
6098  if (xev.type == GDK_DESTROY)
6099  ev.fType = kDestroyNotify;
6100  if (xev.type == GDK_SELECTION_CLEAR)
6101  ev.fType = kSelectionClear;
6102  if (xev.type == GDK_SELECTION_REQUEST)
6103  ev.fType = kSelectionRequest;
6104  if (xev.type == GDK_SELECTION_NOTIFY)
6105  ev.fType = kSelectionNotify;
6106 
6107  ev.fSendEvent = kFALSE; //xev.any.send_event ? kTRUE : kFALSE;
6108  ev.fTime = gdk_event_get_time((GdkEvent *)&xev);
6109  ev.fWindow = (Window_t) xev.any.window;
6110 
6111  if ((xev.type == GDK_MAP) || (xev.type == GDK_UNMAP)) {
6112  ev.fWindow = (Window_t) xev.any.window;
6113  }
6114  if (xev.type == GDK_DELETE) {
6115  ev.fWindow = (Window_t) xev.any.window;
6116  ev.fType = kClientMessage;
6117  ev.fFormat = 32;
6118  ev.fHandle = gWM_DELETE_WINDOW;
6119  ev.fUser[0] = (Long_t) gWM_DELETE_WINDOW;
6120  if (sizeof(ev.fUser[0]) > 4) {
6121  AsmLong(xev.client.data.l[1], xev.client.data.l[3],
6122  ev.fUser[1]);
6123  AsmLong(xev.client.data.l[2], xev.client.data.l[4],
6124  ev.fUser[2]);
6125  } else {
6126  ev.fUser[1] = 0; //xev.client.data.l[1];
6127  ev.fUser[2] = 0; //xev.client.data.l[2];
6128  ev.fUser[3] = 0; //xev.client.data.l[3];
6129  ev.fUser[4] = 0; //xev.client.data.l[4];
6130  }
6131  }
6132  if (xev.type == GDK_DESTROY) {
6133  ev.fType = kDestroyNotify;
6134  ev.fHandle = (Window_t) xev.any.window; // window to be destroyed
6135  ev.fWindow = (Window_t) xev.any.window;
6136  }
6137  if (xev.type == GDK_FOCUS_CHANGE) {
6138  ev.fWindow = (Window_t) xev.focus_change.window;
6139  ev.fCode = kNotifyNormal;
6140  ev.fState = 0;
6141  if (xev.focus_change.in == TRUE) {
6142  ev.fType = kFocusIn;
6143  } else {
6144  ev.fType = kFocusOut;
6145  }
6146  }
6147  if (ev.fType == kGKeyPress || ev.fType == kKeyRelease) {
6148  ev.fWindow = (Window_t) xev.key.window;
6149  MapModifierState(ev.fState, xev.key.state, kFALSE); // key mask
6150  ev.fCode = xev.key.keyval; // key code
6151  ev.fUser[1] = xev.key.length;
6152  if (xev.key.length > 0) ev.fUser[2] = xev.key.string[0];
6153  if (xev.key.length > 1) ev.fUser[3] = xev.key.string[1];
6154  if (xev.key.length > 2) ev.fUser[4] = xev.key.string[2];
6155  HWND tmpwin = (HWND) GetWindow((HWND) GDK_DRAWABLE_XID((GdkWindow *)xev.key.window), GW_CHILD);
6156  if (tmpwin) {
6157  ev.fUser[0] = (ULong_t) gdk_xid_table_lookup((HANDLE)tmpwin);
6158  } else {
6159  ev.fUser[0] = (ULong_t) xev.key.window;
6160  }
6161  }
6162  if (ev.fType == kButtonPress || ev.fType == kButtonRelease) {
6163  ev.fWindow = (Window_t) xev.button.window;
6164  ev.fX = xev.button.x;
6165  ev.fY = xev.button.y;
6166  ev.fXRoot = xev.button.x_root;
6167  ev.fYRoot = xev.button.y_root;
6168  MapModifierState(ev.fState, xev.button.state, kFALSE); // button mask
6169  ev.fCode = xev.button.button; // button code
6170  POINT tpoint;
6171  tpoint.x = xev.button.x;
6172  tpoint.y = xev.button.y;
6173  HWND tmpwin = ChildWindowFromPoint((HWND) GDK_DRAWABLE_XID((GdkWindow *)xev.button.window), tpoint);
6174  if (tmpwin) {
6175  ev.fUser[0] = (ULong_t) gdk_xid_table_lookup((HANDLE)tmpwin);
6176  } else {
6177  ev.fUser[0] = (ULong_t) 0;
6178  }
6179  }
6180  if (ev.fType == kMotionNotify) {
6181  ev.fWindow = (Window_t) xev.motion.window;
6182  ev.fX = xev.motion.x;
6183  ev.fY = xev.motion.y;
6184  ev.fXRoot = xev.motion.x_root;
6185  ev.fYRoot = xev.motion.y_root;
6186  MapModifierState(ev.fState, xev.motion.state, kFALSE); // key or button mask
6187 
6188  POINT tpoint;
6189  tpoint.x = xev.button.x;
6190  tpoint.y = xev.button.y;
6191  HWND tmpwin = ChildWindowFromPoint((HWND) GDK_DRAWABLE_XID((GdkWindow *)xev.motion.window), tpoint);
6192  if (tmpwin) {
6193  ev.fUser[0] = (ULong_t)gdk_xid_table_lookup((HANDLE)tmpwin);
6194  } else {
6195  ev.fUser[0] = (ULong_t) xev.motion.window;
6196  }
6197  }
6198  if (ev.fType == kEnterNotify || ev.fType == kLeaveNotify) {
6199  ev.fWindow = (Window_t) xev.crossing.window;
6200  ev.fX = xev.crossing.x;
6201  ev.fY = xev.crossing.y;
6202  ev.fXRoot = xev.crossing.x_root;
6203  ev.fYRoot = xev.crossing.y_root;
6204  ev.fCode = xev.crossing.mode; // NotifyNormal, NotifyGrab, NotifyUngrab
6205  MapModifierState(ev.fState, xev.crossing.state, kFALSE); // key or button mask
6206  }
6207  if (ev.fType == kExpose) {
6208  ev.fWindow = (Window_t) xev.expose.window;
6209  ev.fX = xev.expose.area.x;
6210  ev.fY = xev.expose.area.y;
6211  ev.fWidth = xev.expose.area.width; // width and
6212  ev.fHeight = xev.expose.area.height; // height of exposed area
6213  ev.fCount = xev.expose.count; // number of expose events still to come
6214  }
6215  if (ev.fType == kConfigureNotify) {
6216  ev.fWindow = (Window_t) xev.configure.window;
6217  ev.fX = xev.configure.x;
6218  ev.fY = xev.configure.y;
6219  ev.fWidth = xev.configure.width;
6220  ev.fHeight = xev.configure.height;
6221  }
6222  if (xev.type == GDK_CLIENT_EVENT) {
6223  ev.fWindow = (Window_t) xev.client.window;
6224  ev.fType = kClientMessage;
6225  ev.fHandle = xev.client.message_type;
6226  ev.fFormat = xev.client.data_format;
6227  ev.fUser[0] = xev.client.data.l[0];
6228  if (sizeof(ev.fUser[0]) > 4) {
6229  AsmLong(xev.client.data.l[1], xev.client.data.l[3],
6230  ev.fUser[1]);
6231  AsmLong(xev.client.data.l[2], xev.client.data.l[4],
6232  ev.fUser[2]);
6233  } else {
6234  ev.fUser[1] = xev.client.data.l[1];
6235  ev.fUser[2] = xev.client.data.l[2];
6236  ev.fUser[3] = xev.client.data.l[3];
6237  ev.fUser[4] = xev.client.data.l[4];
6238  }
6239  }
6240  if (ev.fType == kSelectionClear) {
6241  ev.fWindow = (Window_t) xev.selection.window;
6242  ev.fUser[0] = xev.selection.selection;
6243  }
6244  if (ev.fType == kSelectionRequest) {
6245  ev.fWindow = (Window_t) xev.selection.window;
6246  ev.fUser[0] = (ULong_t) xev.selection.window;
6247  ev.fUser[1] = xev.selection.selection;
6248  ev.fUser[2] = xev.selection.target;
6249  ev.fUser[3] = xev.selection.property;
6250  }
6251  if (ev.fType == kSelectionNotify) {
6252  ev.fWindow = (Window_t) xev.selection.window;
6253  ev.fUser[0] = (ULong_t) xev.selection.window;
6254  ev.fUser[1] = xev.selection.selection;
6255  ev.fUser[2] = xev.selection.target;
6256  ev.fUser[3] = xev.selection.property;
6257  }
6258  if (xev.type == GDK_SCROLL) {
6259  ev.fType = kButtonRelease;
6260  if (xev.scroll.direction == GDK_SCROLL_UP) {
6261  ev.fCode = kButton4;
6262  } else if (xev.scroll.direction == GDK_SCROLL_DOWN) {
6263  ev.fCode = kButton5;
6264  }
6265  ev.fWindow = (Window_t) xev.scroll.window;
6266  ev.fX = xev.scroll.x;
6267  ev.fY = xev.scroll.y;
6268  ev.fXRoot = xev.scroll.x_root;
6269  ev.fYRoot = xev.scroll.y_root;
6270  POINT tpoint;
6271  tpoint.x = xev.scroll.x;
6272  tpoint.y = xev.scroll.y;
6273  HWND tmpwin = ChildWindowFromPoint((HWND) GDK_DRAWABLE_XID((GdkWindow *)xev.scroll.window), tpoint);
6274  if (tmpwin) {
6275  ev.fUser[0] = (ULong_t)gdk_xid_table_lookup((HANDLE)tmpwin);
6276  } else {
6277  ev.fUser[0] = (ULong_t) 0;
6278  }
6279  }
6280  }
6281 }
6282 
6283 ////////////////////////////////////////////////////////////////////////////////
6284 ///
6285 
6286 void TGWin32::Bell(Int_t percent)
6287 {
6288  gSystem->Beep();
6289 }
6290 
6291 ////////////////////////////////////////////////////////////////////////////////
6292 /// Copy a drawable (i.e. pixmap) to another drawable (pixmap, window).
6293 /// The graphics context gc will be used and the source will be copied
6294 /// from src_x,src_y,src_x+width,src_y+height to dest_x,dest_y.
6295 
6296 void TGWin32::CopyArea(Drawable_t src, Drawable_t dest, GContext_t gc,
6297  Int_t src_x, Int_t src_y, UInt_t width,
6298  UInt_t height, Int_t dest_x, Int_t dest_y)
6299 {
6300  if (!src || !dest) return;
6301 
6302  gdk_window_copy_area((GdkDrawable *) dest, (GdkGC *) gc, dest_x, dest_y,
6303  (GdkDrawable *) src, src_x, src_y, width, height);
6304 }
6305 
6306 ////////////////////////////////////////////////////////////////////////////////
6307 /// Change window attributes.
6308 
6309 void TGWin32::ChangeWindowAttributes(Window_t id, SetWindowAttributes_t * attr)
6310 {
6311  if (!id) return;
6312 
6313  GdkColor color;
6314  UInt_t xevmask;
6315  Mask_t evmask;
6316 
6317  if (attr && (attr->fMask & kWAEventMask)) {
6318  evmask = (Mask_t) attr->fEventMask;
6319  MapEventMask(evmask, xevmask);
6320  gdk_window_set_events((GdkWindow *) id, (GdkEventMask) xevmask);
6321  }
6322  if (attr && (attr->fMask & kWABackPixel)) {
6323  color.pixel = attr->fBackgroundPixel;
6324  color.red = GetRValue(attr->fBackgroundPixel);
6325  color.green = GetGValue(attr->fBackgroundPixel);
6326  color.blue = GetBValue(attr->fBackgroundPixel);
6327  gdk_window_set_background((GdkWindow *) id, &color);
6328  }
6329 // if (attr && (attr->fMask & kWAOverrideRedirect))
6330 // gdk_window_set_override_redirect ((GdkWindow *) id, attr->fOverrideRedirect);
6331  if (attr && (attr->fMask & kWABackPixmap)) {
6332  gdk_window_set_back_pixmap((GdkWindow *) id,
6333  (GdkPixmap *) attr->fBackgroundPixmap, 0);
6334  }
6335  if (attr && (attr->fMask & kWACursor)) {
6336  gdk_window_set_cursor((GdkWindow *) id, (GdkCursor *) attr->fCursor);
6337  }
6338  if (attr && (attr->fMask & kWAColormap)) {
6339  gdk_window_set_colormap((GdkWindow *) id,(GdkColormap *) attr->fColormap);
6340  }
6341  if (attr && (attr->fMask & kWABorderWidth)) {
6342  if (attr->fBorderWidth > 0) {
6343  gdk_window_set_decorations((GdkWindow *) id,
6344  (GdkWMDecoration) GDK_DECOR_BORDER);
6345  }
6346  }
6347 }
6348 
6349 ////////////////////////////////////////////////////////////////////////////////
6350 /// This function alters the property for the specified window and
6351 /// causes the X server to generate a PropertyNotify event on that
6352 /// window.
6353 
6354 void TGWin32::ChangeProperty(Window_t id, Atom_t property, Atom_t type,
6355  UChar_t * data, Int_t len)
6356 {
6357  if (!id) return;
6358 
6359  gdk_property_change((GdkWindow *) id, (GdkAtom) property,
6360  (GdkAtom) type, 8, GDK_PROP_MODE_REPLACE, data,len);
6361 }
6362 
6363 ////////////////////////////////////////////////////////////////////////////////
6364 /// Draw a line.
6365 
6366 void TGWin32::DrawLine(Drawable_t id, GContext_t gc, Int_t x1, Int_t y1,
6367  Int_t x2, Int_t y2)
6368 {
6369  if (!id) return;
6370 
6371  gdk_draw_line((GdkDrawable *) id, (GdkGC *) gc, x1, y1, x2, y2);
6372 }
6373 
6374 ////////////////////////////////////////////////////////////////////////////////
6375 /// Clear a window area to the bakcground color.
6376 
6377 void TGWin32::ClearArea(Window_t id, Int_t x, Int_t y, UInt_t w, UInt_t h)
6378 {
6379  if (!id) return;
6380 
6381  gdk_window_clear_area((GdkWindow *) id, x, y, w, h);
6382 }
6383 
6384 ////////////////////////////////////////////////////////////////////////////////
6385 /// Tell WM to send message when window is closed via WM.
6386 
6387 void TGWin32::WMDeleteNotify(Window_t id)
6388 {
6389  if (!id) return;
6390 
6391  Atom prop;
6392  prop = (Atom_t) gdk_atom_intern("WM_DELETE_WINDOW", FALSE);
6393 
6394  W32ChangeProperty((HWND) GDK_DRAWABLE_XID((GdkWindow *) id),
6395  prop, XA_ATOM, 32, GDK_PROP_MODE_REPLACE,
6396  (unsigned char *) &gWM_DELETE_WINDOW, 1);
6397 }
6398 
6399 ////////////////////////////////////////////////////////////////////////////////
6400 /// Turn key auto repeat on or off.
6401 
6402 void TGWin32::SetKeyAutoRepeat(Bool_t on)
6403 {
6404  if (on) {
6405  gdk_key_repeat_restore();
6406  } else {
6407  gdk_key_repeat_disable();
6408  }
6409 }
6410 
6411 ////////////////////////////////////////////////////////////////////////////////
6412 /// Establish passive grab on a certain key. That is, when a certain key
6413 /// keycode is hit while certain modifier's (Shift, Control, Meta, Alt)
6414 /// are active then the keyboard will be grabed for window id.
6415 /// When grab is false, ungrab the keyboard for this key and modifier.
6416 
6417 void TGWin32::GrabKey(Window_t id, Int_t keycode, UInt_t modifier, Bool_t grab)
6418 {
6419  UInt_t xmod;
6420 
6421  MapModifierState(modifier, xmod);
6422 
6423  if (grab) {
6424  gdk_key_grab(keycode, (GdkEventMask)xmod, (GdkWindow *)id);
6425  } else {
6426  gdk_key_ungrab(keycode, (GdkEventMask)xmod, (GdkWindow *)id);
6427  }
6428 }
6429 
6430 ////////////////////////////////////////////////////////////////////////////////
6431 /// Establish passive grab on a certain mouse button. That is, when a
6432 /// certain mouse button is hit while certain modifier's (Shift, Control,
6433 /// Meta, Alt) are active then the mouse will be grabed for window id.
6434 /// When grab is false, ungrab the mouse button for this button and modifier.
6435 
6436 void TGWin32::GrabButton(Window_t id, EMouseButton button, UInt_t modifier,
6437  UInt_t evmask, Window_t confine, Cursor_t cursor,
6438  Bool_t grab)
6439 {
6440  UInt_t xevmask;
6441  UInt_t xmod;
6442 
6443  if (!id) return;
6444 
6445  MapModifierState(modifier, xmod);
6446 
6447  if (grab) {
6448  MapEventMask(evmask, xevmask);
6449  gdk_button_grab(button, xmod, ( GdkWindow *)id, 1, (GdkEventMask)xevmask,
6450  (GdkWindow*)confine, (GdkCursor*)cursor);
6451  } else {
6452  gdk_button_ungrab(button, xmod, ( GdkWindow *)id);
6453  }
6454 }
6455 
6456 ////////////////////////////////////////////////////////////////////////////////
6457 /// Establish an active pointer grab. While an active pointer grab is in
6458 /// effect, further pointer events are only reported to the grabbing
6459 /// client window.
6460 
6461 void TGWin32::GrabPointer(Window_t id, UInt_t evmask, Window_t confine,
6462  Cursor_t cursor, Bool_t grab, Bool_t owner_events)
6463 {
6464  UInt_t xevmask;
6465  MapEventMask(evmask, xevmask);
6466 
6467  if (grab) {
6468  if(!::IsWindowVisible((HWND)GDK_DRAWABLE_XID(id))) return;
6469  gdk_pointer_grab((GdkWindow *) id, owner_events, (GdkEventMask) xevmask,
6470  (GdkWindow *) confine, (GdkCursor *) cursor,
6471  GDK_CURRENT_TIME);
6472  } else {
6473  gdk_pointer_ungrab(GDK_CURRENT_TIME);
6474  ::SetCursor((HCURSOR)GDK_CURSOR_XID(fCursors[kPointer]));
6475  }
6476 }
6477 
6478 ////////////////////////////////////////////////////////////////////////////////
6479 /// Set window name.
6480 
6481 void TGWin32::SetWindowName(Window_t id, char *name)
6482 {
6483  if (!id) return;
6484 
6485  gdk_window_set_title((GdkWindow *) id, name);
6486 }
6487 
6488 ////////////////////////////////////////////////////////////////////////////////
6489 /// Set window icon name.
6490 
6491 void TGWin32::SetIconName(Window_t id, char *name)
6492 {
6493  if (!id) return;
6494 
6495  gdk_window_set_icon_name((GdkWindow *) id, name);
6496 }
6497 
6498 ////////////////////////////////////////////////////////////////////////////////
6499 /// Set pixmap the WM can use when the window is iconized.
6500 
6501 void TGWin32::SetIconPixmap(Window_t id, Pixmap_t pic)
6502 {
6503  if (!id) return;
6504 
6505  gdk_window_set_icon((GdkWindow *)id, NULL, (GdkPixmap *)pic, (GdkPixmap *)pic);
6506 }
6507 
6508 #define safestrlen(s) ((s) ? strlen(s) : 0)
6509 
6510 ////////////////////////////////////////////////////////////////////////////////
6511 /// Set the windows class and resource name.
6512 
6513 void TGWin32::SetClassHints(Window_t id, char *className, char *resourceName)
6514 {
6515  if (!id) return;
6516 
6517  char *class_string;
6518  char *s;
6519  int len_nm, len_cl;
6520  GdkAtom prop;
6521 
6522  prop = gdk_atom_intern("WM_CLASS", kFALSE);
6523 
6524  len_nm = safestrlen(resourceName);
6525  len_cl = safestrlen(className);
6526 
6527  if ((class_string = s =
6528  (char *) malloc((unsigned) (len_nm + len_cl + 2)))) {
6529  if (len_nm) {
6530  strcpy(s, resourceName);
6531  s += len_nm + 1;
6532  } else
6533  *s++ = '\0';
6534  if (len_cl) {
6535  strcpy(s, className);
6536  } else {
6537  *s = '\0';
6538  }
6539 
6540  W32ChangeProperty((HWND) GDK_DRAWABLE_XID((GdkWindow *) id),
6541  (Atom) XA_WM_CLASS, (Atom) XA_WM_CLASS, 8,
6542  GDK_PROP_MODE_REPLACE,
6543  (unsigned char *) class_string,
6544  len_nm + len_cl + 2);
6545  free(class_string);
6546  }
6547 }
6548 
6549 ////////////////////////////////////////////////////////////////////////////////
6550 /// Set decoration style for MWM-compatible wm (mwm, ncdwm, fvwm?).
6551 
6552 void TGWin32::SetMWMHints(Window_t id, UInt_t value, UInt_t funcs,
6553  UInt_t input)
6554 {
6555  if (!id) return;
6556 
6557  gdk_window_set_decorations((GdkDrawable *) id, (GdkWMDecoration) value);
6558  gdk_window_set_functions((GdkDrawable *) id, (GdkWMFunction) funcs);
6559 }
6560 
6561 ////////////////////////////////////////////////////////////////////////////////
6562 ///
6563 
6564 void TGWin32::SetWMPosition(Window_t id, Int_t x, Int_t y)
6565 {
6566  if (!id) return;
6567 
6568  gdk_window_move((GdkDrawable *) id, x, y);
6569 }
6570 
6571 ////////////////////////////////////////////////////////////////////////////////
6572 ///
6573 
6574 void TGWin32::SetWMSize(Window_t id, UInt_t w, UInt_t h)
6575 {
6576  if (!id) return;
6577 
6578  gdk_window_resize((GdkWindow *) id, w, h);
6579 }
6580 
6581 ////////////////////////////////////////////////////////////////////////////////
6582 /// Give the window manager minimum and maximum size hints. Also
6583 /// specify via winc and hinc the resize increments.
6584 
6585 void TGWin32::SetWMSizeHints(Window_t id, UInt_t wmin, UInt_t hmin,
6586  UInt_t wmax, UInt_t hmax,
6587  UInt_t winc, UInt_t hinc)
6588 {
6589  if (!id) return;
6590 
6591  GdkGeometry hints;
6592  GdkWindowHints flags;
6593 
6594  flags = (GdkWindowHints) (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE |
6595  GDK_HINT_RESIZE_INC);
6596  hints.min_width = (Int_t) wmin;
6597  hints.max_width = (Int_t) wmax;
6598  hints.min_height = (Int_t) hmin;
6599  hints.max_height = (Int_t) hmax;
6600  hints.width_inc = (Int_t) winc;
6601  hints.height_inc = (Int_t) hinc;
6602 
6603  gdk_window_set_geometry_hints((GdkWindow *) id, (GdkGeometry *) &hints,
6604  (GdkWindowHints) flags);
6605 }
6606 
6607 ////////////////////////////////////////////////////////////////////////////////
6608 /// Set the initial state of the window. Either kNormalState or kIconicState.
6609 
6610 void TGWin32::SetWMState(Window_t id, EInitialState state)
6611 {
6612  if (!id) return;
6613 
6614 #if 0
6615  XWMHints hints;
6616  Int_t xstate = NormalState;
6617 
6618  if (state == kNormalState)
6619  xstate = NormalState;
6620  if (state == kIconicState)
6621  xstate = IconicState;
6622 
6623  hints.flags = StateHint;
6624  hints.initial_state = xstate;
6625 
6626  XSetWMHints((GdkWindow *) id, &hints);
6627 #endif
6628 }
6629 
6630 ////////////////////////////////////////////////////////////////////////////////
6631 /// Tell window manager that window is a transient window of gdk_parent_root.
6632 
6633 void TGWin32::SetWMTransientHint(Window_t id, Window_t main_id)
6634 {
6635  if (!id) return;
6636 
6637  gdk_window_set_transient_for((GdkWindow *) id, (GdkWindow *) main_id);
6638 }
6639 
6640 ////////////////////////////////////////////////////////////////////////////////
6641 /// Draw a string using a specific graphics context in position (x,y).
6642 
6643 void TGWin32::DrawString(Drawable_t id, GContext_t gc, Int_t x, Int_t y,
6644  const char *s, Int_t len)
6645 {
6646  if (!id) return;
6647 
6648  GdkGCValues values;
6649  gdk_gc_get_values((GdkGC *) gc, &values);
6650  gdk_win32_draw_text((GdkDrawable *) id, (GdkFont *) values.font,
6651  (GdkGC *) gc, x, y, (const gchar *)s, len);
6652 }
6653 
6654 ////////////////////////////////////////////////////////////////////////////////
6655 /// Return length of string in pixels. Size depends on font.
6656 
6657 Int_t TGWin32::TextWidth(FontStruct_t font, const char *s, Int_t len)
6658 {
6659  return gdk_text_width((GdkFont *)font, s, len);
6660 }
6661 
6662 ////////////////////////////////////////////////////////////////////////////////
6663 /// Return some font properties.
6664 
6665 void TGWin32::GetFontProperties(FontStruct_t font, Int_t & max_ascent,
6666  Int_t & max_descent)
6667 {
6668  GdkFont *f = (GdkFont *) font;
6669  max_ascent = f->ascent;
6670  max_descent = f->descent;
6671 }
6672 
6673 ////////////////////////////////////////////////////////////////////////////////
6674 /// Get current values from graphics context gc. Which values of the
6675 /// context to get is encoded in the GCValues::fMask member.
6676 
6677 void TGWin32::GetGCValues(GContext_t gc, GCValues_t & gval)
6678 {
6679  GdkGCValues xgval;
6680  ULong_t xmask;
6681 
6682  MapGCValues(gval, xmask, xgval, kTRUE);
6683  gdk_gc_get_values((GdkGC *) gc, &xgval);
6684  MapGCValues(gval, xmask, xgval, kFALSE);
6685 }
6686 
6687 ////////////////////////////////////////////////////////////////////////////////
6688 /// Retrieve associated font structure once we have the font handle.
6689 /// Free returned FontStruct_t using FreeFontStruct().
6690 
6691 FontStruct_t TGWin32::GetFontStruct(FontH_t fh)
6692 {
6693  return (FontStruct_t) gdk_font_ref((GdkFont *) fh);
6694 }
6695 
6696 ////////////////////////////////////////////////////////////////////////////////
6697 /// Free font structure returned by GetFontStruct().
6698 
6699 void TGWin32::FreeFontStruct(FontStruct_t fs)
6700 {
6701  gdk_font_unref((GdkFont *) fs);
6702 }
6703 
6704 ////////////////////////////////////////////////////////////////////////////////
6705 /// Clear window.
6706 
6707 void TGWin32::ClearWindow(Window_t id)
6708 {
6709  if (!id) return;
6710 
6711  gdk_window_clear((GdkDrawable *) id);
6712 }
6713 
6714 ////////////////////////////////////////////////////////////////////////////////
6715 /// Convert a keysym to the appropriate keycode. For example keysym is
6716 /// a letter and keycode is the matching keyboard key (which is dependend
6717 /// on the current keyboard mapping).
6718 
6719 Int_t TGWin32::KeysymToKeycode(UInt_t keysym)
6720 {
6721  UInt_t xkeysym;
6722  MapKeySym(keysym, xkeysym);
6723  return xkeysym;
6724 }
6725 
6726 ////////////////////////////////////////////////////////////////////////////////
6727 /// Draw a filled rectangle. Filling is done according to the gc.
6728 
6729 void TGWin32::FillRectangle(Drawable_t id, GContext_t gc, Int_t x, Int_t y,
6730  UInt_t w, UInt_t h)
6731 {
6732  if (!id) return;
6733 
6734  gdk_win32_draw_rectangle((GdkDrawable *) id, (GdkGC *) gc, kTRUE, x, y, w, h);
6735 }
6736 
6737 ////////////////////////////////////////////////////////////////////////////////
6738 /// Draw a rectangle outline.
6739 
6740 void TGWin32::DrawRectangle(Drawable_t id, GContext_t gc, Int_t x, Int_t y,
6741  UInt_t w, UInt_t h)
6742 {
6743  if (!id) return;
6744 
6745  gdk_win32_draw_rectangle((GdkDrawable *) id, (GdkGC *) gc, kFALSE, x, y, w, h);
6746 }
6747 
6748 ////////////////////////////////////////////////////////////////////////////////
6749 /// Draws multiple line segments. Each line is specified by a pair of points.
6750 
6751 void TGWin32::DrawSegments(Drawable_t id, GContext_t gc, Segment_t * seg,
6752  Int_t nseg)
6753 {
6754  if (!id) return;
6755 
6756  gdk_win32_draw_segments((GdkDrawable *) id, (GdkGC *) gc, (GdkSegment *)seg, nseg);
6757 }
6758 
6759 ////////////////////////////////////////////////////////////////////////////////
6760 /// Defines which input events the window is interested in. By default
6761 /// events are propageted up the window stack. This mask can also be
6762 /// set at window creation time via the SetWindowAttributes_t::fEventMask
6763 /// attribute.
6764 
6765 void TGWin32::SelectInput(Window_t id, UInt_t evmask)
6766 {
6767  if (!id) return;
6768 
6769  UInt_t xevmask;
6770  MapEventMask(evmask, xevmask, kTRUE);
6771  gdk_window_set_events((GdkWindow *) id, (GdkEventMask)xevmask);
6772 }
6773 
6774 ////////////////////////////////////////////////////////////////////////////////
6775 /// Returns the window id of the window having the input focus.
6776 
6777 Window_t TGWin32::GetInputFocus()
6778 {
6779  HWND hwnd = ::GetFocus();
6780  return (Window_t) gdk_xid_table_lookup(hwnd);
6781 }
6782 
6783 ////////////////////////////////////////////////////////////////////////////////
6784 /// Set keyboard input focus to window id.
6785 
6786 void TGWin32::SetInputFocus(Window_t id)
6787 {
6788  if (!id) return;
6789 
6790  HWND hwnd = (HWND)GDK_DRAWABLE_XID((GdkWindow *)id);
6791  ::SetFocus(hwnd);
6792 }
6793 
6794 ////////////////////////////////////////////////////////////////////////////////
6795 /// Returns the window id of the current owner of the primary selection.
6796 /// That is the window in which, for example some text is selected.
6797 
6798 Window_t TGWin32::GetPrimarySelectionOwner()
6799 {
6800  return (Window_t)gdk_selection_owner_get(gClipboardAtom);
6801 }
6802 
6803 ////////////////////////////////////////////////////////////////////////////////
6804 /// Makes the window id the current owner of the primary selection.
6805 /// That is the window in which, for example some text is selected.
6806 
6807 void TGWin32::SetPrimarySelectionOwner(Window_t id)
6808 {
6809  if (!id) return;
6810 
6811  gdk_selection_owner_set((GdkWindow *) id, gClipboardAtom, GDK_CURRENT_TIME, 0);
6812 }
6813 
6814 ////////////////////////////////////////////////////////////////////////////////
6815 /// XConvertSelection() causes a SelectionRequest event to be sent to the
6816 /// current primary selection owner. This event specifies the selection
6817 /// property (primary selection), the format into which to convert that
6818 /// data before storing it (target = XA_STRING), the property in which
6819 /// the owner will place the information (sel_property), the window that
6820 /// wants the information (id), and the time of the conversion request
6821 /// (when).
6822 /// The selection owner responds by sending a SelectionNotify event, which
6823 /// confirms the selected atom and type.
6824 
6825 void TGWin32::ConvertPrimarySelection(Window_t id, Atom_t clipboard, Time_t when)
6826 {
6827  if (!id) return;
6828 
6829  gdk_selection_convert((GdkWindow *) id, clipboard,
6830  gdk_atom_intern("GDK_TARGET_STRING", 0), when);
6831 }
6832 
6833 ////////////////////////////////////////////////////////////////////////////////
6834 /// Convert the keycode from the event structure to a key symbol (according
6835 /// to the modifiers specified in the event structure and the current
6836 /// keyboard mapping). In buf a null terminated ASCII string is returned
6837 /// representing the string that is currently mapped to the key code.
6838 
6839 void TGWin32::LookupString(Event_t * event, char *buf, Int_t buflen,
6840  UInt_t & keysym)
6841 {
6842  _lookup_string(event, buf, buflen);
6843  UInt_t ks, xks = (UInt_t) event->fCode;
6844  MapKeySym(ks, xks, kFALSE);
6845  keysym = (Int_t) ks;
6846 }
6847 
6848 ////////////////////////////////////////////////////////////////////////////////
6849 /// Map to and from X key symbols. Keysym are the values returned by
6850 /// XLookUpString.
6851 
6852 void TGWin32::MapKeySym(UInt_t & keysym, UInt_t & xkeysym, Bool_t tox)
6853 {
6854  if (tox) {
6855  xkeysym = GDK_VoidSymbol;
6856  if (keysym < 127) {
6857  xkeysym = keysym;
6858  } else if (keysym >= kKey_F1 && keysym <= kKey_F35) {
6859  xkeysym = GDK_F1 + (keysym - (UInt_t) kKey_F1); // function keys
6860  } else {
6861  for (int i = 0; gKeyMap[i].fKeySym; i++) { // any other keys
6862  if (keysym == (UInt_t) gKeyMap[i].fKeySym) {
6863  xkeysym = (UInt_t) gKeyMap[i].fXKeySym;
6864  break;
6865  }
6866  }
6867  }
6868  } else {
6869  keysym = kKey_Unknown;
6870  // commentary in X11/keysymdef says that X codes match ASCII
6871  if (xkeysym < 127) {
6872  keysym = xkeysym;
6873  } else if (xkeysym >= GDK_F1 && xkeysym <= GDK_F35) {
6874  keysym = kKey_F1 + (xkeysym - GDK_F1); // function keys
6875  } else if (xkeysym >= GDK_KP_0 && xkeysym <= GDK_KP_9) {
6876  keysym = kKey_0 + (xkeysym - GDK_KP_0); // numeric keypad keys
6877  } else {
6878  for (int i = 0; gKeyMap[i].fXKeySym; i++) { // any other keys
6879  if (xkeysym == gKeyMap[i].fXKeySym) {
6880  keysym = (UInt_t) gKeyMap[i].fKeySym;
6881  break;
6882  }
6883  }
6884  }
6885  }
6886 }
6887 
6888 ////////////////////////////////////////////////////////////////////////////////
6889 /// Get contents of paste buffer atom into string. If del is true delete
6890 /// the paste buffer afterwards.
6891 
6892 void TGWin32::GetPasteBuffer(Window_t id, Atom_t atom, TString & text,
6893  Int_t & nchar, Bool_t del)
6894 {
6895  if (!id) return;
6896 
6897  char *data;
6898  int nread, actual_format;
6899 
6900  nread = gdk_selection_property_get((GdkWindow *) id,
6901  (unsigned char **) &data,
6902  (GdkAtom *) & atom, &actual_format);
6903 
6904  if ((nread == 0) || (data == NULL)) {
6905  nchar = 0;
6906  return;
6907  }
6908 
6909  text.Insert(0, (const char *) data);
6910  nchar = 1; //strlen(data);
6911  g_free(data);
6912 
6913  // if (del)
6914  gdk_property_delete((GdkWindow *) id,
6915  gdk_atom_intern("GDK_SELECTION", FALSE));
6916 }
6917 
6918 ////////////////////////////////////////////////////////////////////////////////
6919 /// TranslateCoordinates translates coordinates from the frame of
6920 /// reference of one window to another. If the point is contained
6921 /// in a mapped child of the destination, the id of that child is
6922 /// returned as well.
6923 
6924 void TGWin32::TranslateCoordinates(Window_t src, Window_t dest,
6925  Int_t src_x, Int_t src_y,
6926  Int_t &dest_x, Int_t &dest_y,
6927  Window_t &child)
6928 {
6929  if (!src || !dest) return;
6930 
6931  HWND sw, dw, ch = NULL;
6932  POINT point;
6933  sw = (HWND)GDK_DRAWABLE_XID((GdkWindow *)src);
6934  dw = (HWND)GDK_DRAWABLE_XID((GdkWindow *)dest);
6935  point.x = src_x;
6936  point.y = src_y;
6937  ::MapWindowPoints(sw, // handle of window to be mapped from
6938  dw, // handle to window to be mapped to
6939  &point, // pointer to array with points to map
6940  1); // number of structures in array
6941  ch = ::ChildWindowFromPointEx(dw, point, CWP_SKIPDISABLED | CWP_SKIPINVISIBLE);
6942  child = (Window_t)gdk_xid_table_lookup(ch);
6943 
6944  if (child == src) {
6945  child = (Window_t) 0;
6946  }
6947  dest_x = point.x;
6948  dest_y = point.y;
6949 }
6950 
6951 ////////////////////////////////////////////////////////////////////////////////
6952 /// Return geometry of window (should be called GetGeometry but signature
6953 /// already used).
6954 
6955 void TGWin32::GetWindowSize(Drawable_t id, Int_t & x, Int_t & y,
6956  UInt_t & w, UInt_t & h)
6957 {
6958  if (!id) return;
6959 
6960  Int_t ddum;
6961  if (GDK_DRAWABLE_TYPE(id) == GDK_DRAWABLE_PIXMAP) {
6962  x = y = 0;
6963  gdk_drawable_get_size((GdkDrawable *)id, (int*)&w, (int*)&h);
6964  }
6965  else {
6966  gdk_window_get_geometry((GdkDrawable *) id, &x, &y, (int*)&w,
6967  (int*)&h, &ddum);
6968  }
6969 }
6970 
6971 ////////////////////////////////////////////////////////////////////////////////
6972 /// FillPolygon fills the region closed by the specified path.
6973 /// The path is closed automatically if the last point in the list does
6974 /// not coincide with the first point. All point coordinates are
6975 /// treated as relative to the origin. For every pair of points
6976 /// inside the polygon, the line segment connecting them does not
6977 /// intersect the path.
6978 
6979 void TGWin32::FillPolygon(Window_t id, GContext_t gc, Point_t * points,
6980  Int_t npnt)
6981 {
6982  if (!id) return;
6983 
6984  gdk_win32_draw_polygon((GdkWindow *) id, (GdkGC *) gc, 1, (GdkPoint *) points, npnt);
6985 }
6986 
6987 ////////////////////////////////////////////////////////////////////////////////
6988 /// Returns the root window the pointer is logically on and the pointer
6989 /// coordinates relative to the root window's origin.
6990 /// The pointer coordinates returned to win_x and win_y are relative to
6991 /// the origin of the specified window. In this case, QueryPointer returns
6992 /// the child that contains the pointer, if any, or else kNone to
6993 /// childw. QueryPointer returns the current logical state of the
6994 /// keyboard buttons and the modifier keys in mask.
6995 
6996 void TGWin32::QueryPointer(Window_t id, Window_t &rootw,
6997  Window_t &childw, Int_t &root_x,
6998  Int_t &root_y, Int_t &win_x, Int_t &win_y,
6999  UInt_t &mask)
7000 {
7001  if (!id) return;
7002 
7003  POINT currPt;
7004  HWND chw, window;
7005  UInt_t umask = 0;
7006  BYTE kbd[256];
7007 
7008  window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)id);
7009  rootw = (Window_t)GDK_ROOT_PARENT();
7010  ::GetCursorPos(&currPt);
7011  chw = ::WindowFromPoint(currPt);
7012  childw = (Window_t)gdk_xid_table_lookup(chw);
7013  root_x = currPt.x;
7014  root_y = currPt.y;
7015 
7016  ::ScreenToClient(window, &currPt);
7017  win_x = currPt.x;
7018  win_y = currPt.y;
7019 
7020  ::GetKeyboardState (kbd);
7021 
7022  if (kbd[VK_SHIFT] & 0x80) {
7023  umask |= GDK_SHIFT_MASK;
7024  }
7025  if (kbd[VK_CAPITAL] & 0x80) {
7026  umask |= GDK_LOCK_MASK;
7027  }
7028  if (kbd[VK_CONTROL] & 0x80) {
7029  umask |= GDK_CONTROL_MASK;
7030  }
7031  if (kbd[VK_MENU] & 0x80) {
7032  umask |= GDK_MOD1_MASK;
7033  }
7034  if (kbd[VK_LBUTTON] & 0x80) {
7035  umask |= GDK_BUTTON1_MASK;
7036  }
7037  if (kbd[VK_MBUTTON] & 0x80) {
7038  umask |= GDK_BUTTON2_MASK;
7039  }
7040  if (kbd[VK_RBUTTON] & 0x80) {
7041  umask |= GDK_BUTTON3_MASK;
7042  }
7043 
7044  MapModifierState(mask, umask, kFALSE);
7045 }
7046 
7047 ////////////////////////////////////////////////////////////////////////////////
7048 /// Set foreground color in graphics context (shortcut for ChangeGC with
7049 /// only foreground mask set).
7050 
7051 void TGWin32::SetForeground(GContext_t gc, ULong_t foreground)
7052 {
7053  GdkColor fore;
7054  fore.pixel = foreground;
7055  fore.red = GetRValue(foreground);
7056  fore.green = GetGValue(foreground);
7057  fore.blue = GetBValue(foreground);
7058  gdk_gc_set_foreground((GdkGC *) gc, &fore);
7059 }
7060 
7061 ////////////////////////////////////////////////////////////////////////////////
7062 /// Set clipping rectangles in graphics context. X, Y specify the origin
7063 /// of the rectangles. Recs specifies an array of rectangles that define
7064 /// the clipping mask and n is the number of rectangles.
7065 
7066 void TGWin32::SetClipRectangles(GContext_t gc, Int_t x, Int_t y,
7067  Rectangle_t * recs, Int_t n)
7068 {
7069  Int_t i;
7070  GdkRectangle *grects = new GdkRectangle[n];
7071 
7072  for (i = 0; i < n; i++) {
7073  grects[i].x = x+recs[i].fX;
7074  grects[i].y = y+recs[i].fY;
7075  grects[i].width = recs[i].fWidth;
7076  grects[i].height = recs[i].fHeight;
7077  }
7078 
7079  for (i = 0; i < n; i++) {
7080  gdk_gc_set_clip_rectangle((GdkGC *)gc, (GdkRectangle*)recs);
7081  }
7082  delete [] grects;
7083 }
7084 
7085 ////////////////////////////////////////////////////////////////////////////////
7086 /// Flush (mode = 0, default) or synchronize (mode = 1) X output buffer.
7087 /// Flush flushes output buffer. Sync flushes buffer and waits till all
7088 /// requests have been processed by X server.
7089 
7090 void TGWin32::Update(Int_t mode)
7091 {
7092  GdiFlush();
7093 }
7094 
7095 ////////////////////////////////////////////////////////////////////////////////
7096 /// Create a new empty region.
7097 
7098 Region_t TGWin32::CreateRegion()
7099 {
7100  return (Region_t) gdk_region_new();
7101 }
7102 
7103 ////////////////////////////////////////////////////////////////////////////////
7104 /// Destroy region.
7105 
7106 void TGWin32::DestroyRegion(Region_t reg)
7107 {
7108  gdk_region_destroy((GdkRegion *) reg);
7109 }
7110 
7111 ////////////////////////////////////////////////////////////////////////////////
7112 /// Union of rectangle with a region.
7113 
7114 void TGWin32::UnionRectWithRegion(Rectangle_t * rect, Region_t src, Region_t dest)
7115 {
7116  GdkRectangle r;
7117  r.x = rect->fX;
7118  r.y = rect->fY;
7119  r.width = rect->fWidth;
7120  r.height = rect->fHeight;
7121  dest = (Region_t) gdk_region_union_with_rect((GdkRegion *) src, &r);
7122 }
7123 
7124 ////////////////////////////////////////////////////////////////////////////////
7125 /// Create region for the polygon defined by the points array.
7126 /// If winding is true use WindingRule else EvenOddRule as fill rule.
7127 
7128 Region_t TGWin32::PolygonRegion(Point_t * points, Int_t np, Bool_t winding)
7129 {
7130  return (Region_t) gdk_region_polygon((GdkPoint*)points, np,
7131  winding ? GDK_WINDING_RULE : GDK_EVEN_ODD_RULE);
7132 }
7133 
7134 ////////////////////////////////////////////////////////////////////////////////
7135 /// Compute the union of rega and regb and return result region.
7136 /// The output region may be the same result region.
7137 
7138 void TGWin32::UnionRegion(Region_t rega, Region_t regb, Region_t result)
7139 {
7140  result = (Region_t) gdk_regions_union((GdkRegion *) rega, (GdkRegion *) regb);
7141 }
7142 
7143 ////////////////////////////////////////////////////////////////////////////////
7144 /// Compute the intersection of rega and regb and return result region.
7145 /// The output region may be the same as the result region.
7146 
7147 void TGWin32::IntersectRegion(Region_t rega, Region_t regb,
7148  Region_t result)
7149 {
7150  result = (Region_t) gdk_regions_intersect((GdkRegion *) rega,(GdkRegion *) regb);
7151 }
7152 
7153 ////////////////////////////////////////////////////////////////////////////////
7154 /// Subtract rega from regb.
7155 
7156 void TGWin32::SubtractRegion(Region_t rega, Region_t regb, Region_t result)
7157 {
7158  result = (Region_t)gdk_regions_subtract((GdkRegion *) rega,(GdkRegion *) regb);
7159 }
7160 
7161 ////////////////////////////////////////////////////////////////////////////////
7162 /// Calculate the difference between the union and intersection of
7163 /// two regions.
7164 
7165 void TGWin32::XorRegion(Region_t rega, Region_t regb, Region_t result)
7166 {
7167  result = (Region_t) gdk_regions_xor((GdkRegion *) rega, (GdkRegion *) regb);
7168 }
7169 
7170 ////////////////////////////////////////////////////////////////////////////////
7171 /// Return true if the region is empty.
7172 
7173 Bool_t TGWin32::EmptyRegion(Region_t reg)
7174 {
7175  return (Bool_t) gdk_region_empty((GdkRegion *) reg);
7176 }
7177 
7178 ////////////////////////////////////////////////////////////////////////////////
7179 /// Returns true if the point x,y is in the region.
7180 
7181 Bool_t TGWin32::PointInRegion(Int_t x, Int_t y, Region_t reg)
7182 {
7183  return (Bool_t) gdk_region_point_in((GdkRegion *) reg, x, y);
7184 }
7185 
7186 ////////////////////////////////////////////////////////////////////////////////
7187 /// Returns true if two regions are equal.
7188 
7189 Bool_t TGWin32::EqualRegion(Region_t rega, Region_t regb)
7190 {
7191  return (Bool_t) gdk_region_equal((GdkRegion *) rega, (GdkRegion *) regb);
7192 }
7193 
7194 ////////////////////////////////////////////////////////////////////////////////
7195 /// Return smallest enclosing rectangle.
7196 
7197 void TGWin32::GetRegionBox(Region_t reg, Rectangle_t * rect)
7198 {
7199  GdkRectangle r;
7200  gdk_region_get_clipbox((GdkRegion *) reg, &r);
7201  rect->fX = r.x;
7202  rect->fY = r.y;
7203  rect->fWidth = r.width;
7204  rect->fHeight = r.height;
7205 }
7206 
7207 ////////////////////////////////////////////////////////////////////////////////
7208 /// Return list of font names matching "fontname".
7209 
7210 char **TGWin32::ListFonts(const char *fontname, Int_t /*max*/, Int_t &count)
7211 {
7212  char foundry[32], family[100], weight[32], slant[32], font_name[256];
7213  char **fontlist;
7214  Int_t n1, fontcount = 0;
7215 
7216  sscanf(fontname, "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%n",
7217  foundry, family, weight, slant, &n1);
7218  // replace "medium" by "normal"
7219  if(!stricmp(weight,"medium")) {
7220  sprintf(weight,"normal");
7221  }
7222  // since all sizes are allowed with TTF, just forget it...
7223  sprintf(font_name, "-%s-%s-%s-%s-*", foundry, family, weight, slant);
7224  fontlist = gdk_font_list_new(font_name, &fontcount);
7225  count = fontcount;
7226 
7227  if (fontcount > 0) return fontlist;
7228  return 0;
7229 }
7230 
7231 ////////////////////////////////////////////////////////////////////////////////
7232 ///
7233 
7234 void TGWin32::FreeFontNames(char **fontlist)
7235 {
7236  gdk_font_list_free(fontlist);
7237 }
7238 
7239 ////////////////////////////////////////////////////////////////////////////////
7240 ///
7241 
7242 Drawable_t TGWin32::CreateImage(UInt_t width, UInt_t height)
7243 {
7244  return (Drawable_t) gdk_image_new(GDK_IMAGE_SHARED, gdk_visual_get_best(),
7245  width, height);
7246 }
7247 
7248 ////////////////////////////////////////////////////////////////////////////////
7249 ///
7250 
7251 void TGWin32::GetImageSize(Drawable_t id, UInt_t &width, UInt_t &height)
7252 {
7253  width = ((GdkImage*)id)->width;
7254  height = ((GdkImage*)id)->height;
7255 }
7256 
7257 ////////////////////////////////////////////////////////////////////////////////
7258 ///
7259 
7260 void TGWin32::PutPixel(Drawable_t id, Int_t x, Int_t y, ULong_t pixel)
7261 {
7262  if (!id) return;
7263 
7264  GdkImage *image = (GdkImage *)id;
7265  if (image->depth == 1) {
7266  if (pixel & 1) {
7267  ((UChar_t *) image->mem)[y * image->bpl + (x >> 3)] |= (1 << (7 - (x & 0x7)));
7268  } else {
7269  ((UChar_t *) image->mem)[y * image->bpl + (x >> 3)] &= ~(1 << (7 - (x & 0x7)));
7270  }
7271  } else {
7272  UChar_t *pixelp = (UChar_t *) image->mem + y * image->bpl + x * image->bpp;
7273  // Windows is always LSB, no need to check image->byte_order.
7274  switch (image->bpp) {
7275  case 4:
7276  pixelp[3] = 0;
7277  case 3:
7278  pixelp[2] = ((pixel >> 16) & 0xFF);
7279  case 2:
7280  pixelp[1] = ((pixel >> 8) & 0xFF);
7281  case 1:
7282  pixelp[0] = (pixel & 0xFF);
7283  }
7284  }
7285 }
7286 
7287 ////////////////////////////////////////////////////////////////////////////////
7288 ///
7289 
7290 void TGWin32::PutImage(Drawable_t id, GContext_t gc, Drawable_t img, Int_t dx,
7291  Int_t dy, Int_t x, Int_t y, UInt_t w, UInt_t h)
7292 {
7293  if (!id) return;
7294 
7295  gdk_draw_image((GdkDrawable *) id, (GdkGC *)gc, (GdkImage *)img,
7296  x, y, dx, dy, w, h);
7297  ::GdiFlush();
7298 }
7299 
7300 ////////////////////////////////////////////////////////////////////////////////
7301 ///
7302 
7303 void TGWin32::DeleteImage(Drawable_t img)
7304 {
7305  gdk_image_unref((GdkImage *)img);
7306 }
7307 
7308 ////////////////////////////////////////////////////////////////////////////////
7309 /// Gets DIB bits
7310 /// x, y, width, height - position of bitmap
7311 /// returns a pointer on bitmap bits array
7312 /// in format:
7313 /// b1, g1, r1, 0, b2, g2, r2, 0 ... bn, gn, rn, 0 ..
7314 ///
7315 /// Pixels are numbered from left to right and from top to bottom.
7316 /// By default all pixels from the whole drawable are returned.
7317 
7318 unsigned char *TGWin32::GetColorBits(Drawable_t wid, Int_t x, Int_t y,
7319  UInt_t width, UInt_t height)
7320 {
7321  HDC hdc, memdc;
7322  BITMAPINFO bmi;
7323  HGDIOBJ oldbitmap1, oldbitmap2;
7324  BITMAP bm;
7325  HBITMAP ximage = 0;
7326  VOID *bmbits = 0;
7327  unsigned char *ret = 0;
7328 
7329  if (GDK_DRAWABLE_TYPE(wid) == GDK_DRAWABLE_PIXMAP) {
7330  hdc = ::CreateCompatibleDC(NULL);
7331  oldbitmap1 = ::SelectObject(hdc, GDK_DRAWABLE_XID(wid));
7332  ::GetObject(GDK_DRAWABLE_XID(wid), sizeof(BITMAP), &bm);
7333  } else {
7334  hdc = ::GetDC((HWND)GDK_DRAWABLE_XID(wid));
7335  }
7336  memdc = ::CreateCompatibleDC(hdc);
7337 
7338  bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
7339  bmi.bmiHeader.biWidth = width;
7340  bmi.bmiHeader.biHeight = -1 * (int)(height);
7341  bmi.bmiHeader.biPlanes = 1;
7342  bmi.bmiHeader.biBitCount = 32;
7343  bmi.bmiHeader.biCompression = BI_RGB;
7344  bmi.bmiHeader.biSizeImage = 0;
7345  bmi.bmiHeader.biXPelsPerMeter = bmi.bmiHeader.biYPelsPerMeter = 0;
7346  bmi.bmiHeader.biClrUsed = 0;
7347  bmi.bmiHeader.biClrImportant = 0;
7348 
7349  ximage = ::CreateDIBSection(hdc, (BITMAPINFO *) &bmi, DIB_RGB_COLORS, &bmbits, NULL, 0);
7350 
7351  if (ximage && bmbits) {
7352  oldbitmap2 = ::SelectObject(memdc, ximage);
7353  ::BitBlt(memdc, x, y, width, height, hdc, 0, 0, SRCCOPY);
7354  ::SelectObject(memdc, oldbitmap2);
7355  }
7356  ::DeleteDC(memdc);
7357  if (GDK_DRAWABLE_TYPE(wid) == GDK_DRAWABLE_PIXMAP) {
7358  ::SelectObject(hdc, oldbitmap1);
7359  ::DeleteDC(hdc);
7360  } else {
7361  ::ReleaseDC((HWND)GDK_DRAWABLE_XID(wid), hdc);
7362  }
7363  if (ximage && bmbits) {
7364  ULong_t sz = width*height*4;
7365  ret = new unsigned char[sz];
7366  memcpy(ret, bmbits, sz);
7367  ::DeleteObject(ximage);
7368  }
7369  return ret;
7370 }
7371 
7372 ////////////////////////////////////////////////////////////////////////////////
7373 /// create an image from RGB data. RGB data is in format :
7374 /// b1, g1, r1, 0, b2, g2, r2, 0 ... bn, gn, rn, 0 ..
7375 ///
7376 /// Pixels are numbered from left to right and from top to bottom.
7377 /// Note that data must be 32-bit aligned
7378 
7379 Pixmap_t TGWin32::CreatePixmapFromData(unsigned char *bits, UInt_t width, UInt_t height)
7380 {
7381  BITMAPINFO bmp_info;
7382  bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
7383  bmp_info.bmiHeader.biWidth = width;
7384  bmp_info.bmiHeader.biHeight = -1 * (int)(height);
7385  bmp_info.bmiHeader.biPlanes = 1;
7386  bmp_info.bmiHeader.biBitCount = 32;
7387  bmp_info.bmiHeader.biCompression = BI_RGB;
7388  bmp_info.bmiHeader.biSizeImage = 0;
7389  bmp_info.bmiHeader.biClrUsed = 0;
7390  bmp_info.bmiHeader.biXPelsPerMeter = 0L;
7391  bmp_info.bmiHeader.biYPelsPerMeter = 0L;
7392  bmp_info.bmiHeader.biClrImportant = 0;
7393  bmp_info.bmiColors[0].rgbRed = 0;
7394  bmp_info.bmiColors[0].rgbGreen = 0;
7395  bmp_info.bmiColors[0].rgbBlue = 0;
7396  bmp_info.bmiColors[0].rgbReserved = 0;
7397 
7398  HDC hdc = ::GetDC(NULL);
7399  HBITMAP hbitmap = ::CreateDIBitmap(hdc, &bmp_info.bmiHeader, CBM_INIT,
7400  (void *)bits, &bmp_info, DIB_RGB_COLORS);
7401  ::ReleaseDC(NULL, hdc);
7402 
7403  SIZE size;
7404  // For an obscure reason, we have to set the size of the
7405  // bitmap this way before to call gdk_pixmap_foreign_new
7406  // otherwise, it fails...
7407  ::SetBitmapDimensionEx(hbitmap,width, height, &size);
7408 
7409  return (Pixmap_t)gdk_pixmap_foreign_new((guint32)hbitmap);
7410 }
7411 
7412 ////////////////////////////////////////////////////////////////////////////////
7413 ///register pixmap created by TGWin32GLManager
7414 
7415 Int_t TGWin32::AddPixmap(ULong_t pix, UInt_t w, UInt_t h)
7416 {
7417  HBITMAP hBmp = reinterpret_cast<HBITMAP>(pix);
7418  SIZE sz = SIZE();
7419 
7420  SetBitmapDimensionEx(hBmp, w, h, &sz);
7421  GdkPixmap *newPix = gdk_pixmap_foreign_new(reinterpret_cast<guint32>(hBmp));
7422 
7423  Int_t wid = 0;
7424  for(; wid < fMaxNumberOfWindows; ++wid)
7425  if (!fWindows[wid].open)
7426  break;
7427 
7428  if (wid == fMaxNumberOfWindows) {
7429  Int_t newSize = fMaxNumberOfWindows + 10;
7430 
7431  fWindows = (XWindow_t *)TStorage::ReAlloc(fWindows, newSize * sizeof(XWindow_t),
7432  fMaxNumberOfWindows * sizeof(XWindow_t));
7433 
7434  for (Int_t i = fMaxNumberOfWindows; i < newSize; ++i)
7435  fWindows[i].open = 0;
7436 
7437  fMaxNumberOfWindows = newSize;
7438  }
7439 
7440  fWindows[wid].open = 1;
7441  gCws = fWindows + wid;
7442  gCws->window = newPix;
7443  gCws->drawing = gCws->window;
7444  gCws->buffer = 0;
7445  gCws->double_buffer = 0;
7446  gCws->ispixmap = 1;
7447  gCws->clip = 0;
7448  gCws->width = w;
7449  gCws->height = h;
7450  gCws->new_colors = 0;
7451 
7452  return wid;
7453 }
7454 
7455 ////////////////////////////////////////////////////////////////////////////////
7456 /// Register a window created by Qt as a ROOT window (like InitWindow()).
7457 
7458 Int_t TGWin32::AddWindow(ULong_t qwid, UInt_t w, UInt_t h)
7459 {
7460  Int_t wid;
7461  // Select next free window number
7462 
7463  again:
7464  for (wid = 0; wid < fMaxNumberOfWindows; wid++) {
7465  if (!fWindows[wid].open) {
7466  fWindows[wid].open = 1;
7467  fWindows[wid].double_buffer = 0;
7468  gCws = &fWindows[wid];
7469  break;
7470  }
7471  }
7472 
7473  if (wid == fMaxNumberOfWindows) {
7474  int newsize = fMaxNumberOfWindows + 10;
7475  fWindows =
7476  (XWindow_t *) TStorage::ReAlloc(fWindows,
7477  newsize * sizeof(XWindow_t),
7478  fMaxNumberOfWindows *
7479  sizeof(XWindow_t));
7480 
7481  for (int i = fMaxNumberOfWindows; i < newsize; i++) {
7482  fWindows[i].open = 0;
7483  }
7484 
7485  fMaxNumberOfWindows = newsize;
7486  goto again;
7487  }
7488 
7489  gCws->window = gdk_window_foreign_new((guint32)qwid);
7490 
7491  gCws->drawing = gCws->window;
7492  gCws->buffer = 0;
7493  gCws->double_buffer = 0;
7494  gCws->ispixmap = 0;
7495  gCws->clip = 0;
7496  gCws->width = w;
7497  gCws->height = h;
7498  gCws->new_colors = 0;
7499 
7500  return wid;
7501 }
7502 
7503 ////////////////////////////////////////////////////////////////////////////////
7504 /// Remove a window created by Qt (like CloseWindow1()).
7505 
7506 void TGWin32::RemoveWindow(ULong_t qwid)
7507 {
7508  int wid;
7509 
7510  SelectWindow((int)qwid);
7511 
7512  if (gCws->buffer) {
7513  gdk_pixmap_unref(gCws->buffer);
7514  }
7515  if (gCws->new_colors) {
7516  gdk_colormap_free_colors((GdkColormap *) fColormap,
7517  (GdkColor *)gCws->new_colors, gCws->ncolors);
7518 
7519  delete [] gCws->new_colors;
7520  gCws->new_colors = 0;
7521  }
7522 
7523  GdiFlush();
7524  gCws->open = 0;
7525 
7526  if (!fWindows) return;
7527 
7528  // make first window in list the current window
7529  for (wid = 0; wid < fMaxNumberOfWindows; wid++) {
7530  if (fWindows[wid].open) {
7531  gCws = &fWindows[wid];
7532  return;
7533  }
7534  }
7535  gCws = 0;
7536 }
7537 
7538 ////////////////////////////////////////////////////////////////////////////////
7539 /// The Nonrectangular Window Shape Extension adds nonrectangular
7540 /// windows to the System.
7541 /// This allows for making shaped (partially transparent) windows
7542 
7543 void TGWin32::ShapeCombineMask(Window_t id, Int_t x, Int_t y, Pixmap_t mask)
7544 {
7545  gdk_window_shape_combine_mask((GdkWindow *)id, (GdkBitmap *) mask, x, y);
7546 }
7547 
7548 ////////////////////////////////////////////////////////////////////////////////
7549 /// Returns the width of the screen in millimeters.
7550 
7551 UInt_t TGWin32::ScreenWidthMM() const
7552 {
7553  return (UInt_t)gdk_screen_width_mm();
7554 }
7555 
7556 //------------------------------ Drag and Drop ---------------------------------
7557 
7558 ////////////////////////////////////////////////////////////////////////////////
7559 /// Deletes the specified property on the specified window.
7560 
7561 void TGWin32::DeleteProperty(Window_t win, Atom_t& prop)
7562 {
7563  HWND hWnd = (HWND)GDK_DRAWABLE_XID((GdkWindow *)win);
7564  Atom_t atom = (Atom_t)GetProp(hWnd,(LPCTSTR)MAKELONG(prop,0));
7565  if (atom != 0) {
7566  GlobalDeleteAtom(atom);
7567  }
7568  RemoveProp(hWnd,(LPCTSTR)MAKELONG(prop,0));
7569 }
7570 
7571 ////////////////////////////////////////////////////////////////////////////////
7572 /// Returns the actual type of the property, the actual format of the property,
7573 /// and a pointer to the data actually returned.
7574 
7575 Int_t TGWin32::GetProperty(Window_t win, Atom_t prop, Long_t offset, Long_t len,
7576  Bool_t del, Atom_t req_type, Atom_t *act_type,
7577  Int_t *act_format, ULong_t *nitems, ULong_t *bytes,
7578  unsigned char **prop_list)
7579 {
7580  HGLOBAL hdata;
7581  UChar_t *ptr, *data;
7582  UInt_t i, n, length;
7583 
7584  HWND hWnd = (HWND)GDK_DRAWABLE_XID((GdkWindow *)win);
7585  if (hWnd == NULL)
7586  return 0;
7587 
7588  Atom_t dndproxy = InternAtom("XdndProxy", kFALSE);
7589  Atom_t dndtypelist = InternAtom("XdndTypeList", kFALSE);
7590 
7591  if (prop == dndproxy)
7592  return 0;
7593  if (prop == dndtypelist) {
7594  *act_type = XA_ATOM;
7595  *prop_list = (unsigned char *)GetProp(hWnd, (LPCTSTR)MAKELONG(prop,0));
7596  for (n = 0; prop_list[n]; n++);
7597  *nitems = n;
7598  return n;
7599  }
7600  else {
7601  if (!OpenClipboard((HWND)GDK_DRAWABLE_XID((GdkWindow *)win))) {
7602  return 0;
7603  }
7604  hdata = GetClipboardData(CF_PRIVATEFIRST);
7605  ptr = (UChar_t *)GlobalLock(hdata);
7606  length = GlobalSize(hdata);
7607  data = (UChar_t *)malloc(length + 1);
7608  for (i = 0; i < length; i++) {
7609  data[i] = ptr[i];
7610  }
7611  GlobalUnlock(hdata);
7612  CloseClipboard();
7613  *prop_list = data;
7614  *bytes = *nitems = length;
7615  return length;
7616  }
7617  return 0;
7618 }
7619 
7620 ////////////////////////////////////////////////////////////////////////////////
7621 /// Changes the active cursor of the specified window.
7622 
7623 void TGWin32::ChangeActivePointerGrab(Window_t win, UInt_t mask, Cursor_t cur)
7624 {
7625  UInt_t xevmask;
7626  MapEventMask(mask, xevmask);
7627  if (cur == kNone)
7628  gdk_window_set_cursor((GdkWindow *) win, fCursors[kHand]);
7629  else
7630  gdk_window_set_cursor((GdkWindow *) win, (GdkCursor *)cur);
7631 }
7632 
7633 ////////////////////////////////////////////////////////////////////////////////
7634 /// Get Clipboard data.
7635 
7636 void TGWin32::ConvertSelection(Window_t win, Atom_t &sel, Atom_t &target,
7637  Atom_t &prop, Time_t &stamp)
7638 {
7639  HGLOBAL hdata;
7640 
7641  static UINT gdk_selection_notify_msg =
7642  RegisterWindowMessage("gdk-selection-notify");
7643  HWND hWnd = (HWND)GDK_DRAWABLE_XID((GdkWindow *)win);
7644  if (!OpenClipboard((HWND)GDK_DRAWABLE_XID((GdkWindow *)win))) {
7645  return;
7646  }
7647  hdata = GetClipboardData(CF_PRIVATEFIRST);
7648  CloseClipboard();
7649  if (hdata == 0)
7650  return;
7651  /* Send ourselves an ersatz selection notify message so that we actually
7652  * fetch the data.
7653  */
7654  PostMessage(hWnd, gdk_selection_notify_msg, sel, target);
7655 }
7656 
7657 ////////////////////////////////////////////////////////////////////////////////
7658 /// Assigns owner of Clipboard.
7659 
7660 Bool_t TGWin32::SetSelectionOwner(Window_t owner, Atom_t &sel)
7661 {
7662  static UINT gdk_selection_request_msg =
7663  RegisterWindowMessage("gdk-selection-request");
7664  HWND hWnd = (HWND)GDK_DRAWABLE_XID((GdkWindow *)owner);
7665  OpenClipboard(hWnd);
7666  EmptyClipboard();
7667  CloseClipboard();
7668  if (owner) {
7669  ::PostMessage(hWnd, gdk_selection_request_msg, sel, 0);
7670  }
7671  return kTRUE;
7672 }
7673 
7674 ////////////////////////////////////////////////////////////////////////////////
7675 /// Put data into Clipboard.
7676 
7677 void TGWin32::ChangeProperties(Window_t id, Atom_t property, Atom_t type,
7678  Int_t format, UChar_t *data, Int_t len)
7679 {
7680  HGLOBAL hdata;
7681  Int_t i;
7682  UChar_t *ptr;
7683 
7684  if (data == 0 || len == 0)
7685  return;
7686  if (!OpenClipboard((HWND)GDK_DRAWABLE_XID((GdkWindow *)id))) {
7687  return;
7688  }
7689  hdata = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len + 1);
7690  ptr = (UChar_t *)GlobalLock(hdata);
7691  for (i = 0; i < len; i++) {
7692  *ptr++ = *data++;
7693  }
7694  GlobalUnlock(hdata);
7695  SetClipboardData(CF_PRIVATEFIRST, hdata);
7696  CloseClipboard();
7697 }
7698 
7699 ////////////////////////////////////////////////////////////////////////////////
7700 /// Add the list of drag and drop types to the Window win.
7701 
7702 void TGWin32::SetTypeList(Window_t win, Atom_t prop, Atom_t *typelist)
7703 {
7704  SetProp((HWND)GDK_DRAWABLE_XID((GdkWindow *)win),
7705  (LPCTSTR)MAKELONG(prop,0),
7706  (HANDLE)typelist);
7707 }
7708 
7709 ////////////////////////////////////////////////////////////////////////////////
7710 /// Recursively search in the children of Window for a Window which is at
7711 /// location x, y and is DND aware, with a maximum depth of maxd.
7712 /// Possibility to exclude dragwin and input.
7713 
7714 Window_t TGWin32::FindRWindow(Window_t root, Window_t dragwin, Window_t input,
7715  int x, int y, int maxd)
7716 {
7717  POINT point;
7718  POINT cpt;
7719  RECT rect;
7720  HWND hwnd, hwndc;
7721  HWND hwndt;
7722  Window_t win, retwin = kNone;
7723  Atom_t version = 0;
7724  Atom_t dndaware = InternAtom("XdndAware", kFALSE);
7725 
7726  cpt.x = x;
7727  cpt.y = y;
7728  hwnd = ::ChildWindowFromPointEx((HWND)GDK_DRAWABLE_XID((GdkWindow *)root),
7729  cpt, CWP_ALL);
7730  while (hwnd) {
7731  GetWindowRect(hwnd, &rect);
7732  if (PtInRect(&rect, cpt)) {
7733  if (GetProp(hwnd,(LPCTSTR)MAKELONG(dndaware,0))) {
7734  win = (Window_t) gdk_xid_table_lookup(hwnd);
7735  if (win && win != dragwin && win != input)
7736  return win;
7737  }
7738  Bool_t done = kFALSE;
7739  hwndt = hwnd;
7740  while (!done) {
7741  point = cpt;
7742  ::MapWindowPoints(NULL, hwndt, &point, 1);
7743  hwndc = ChildWindowFromPoint (hwndt, point);
7744  if (GetProp(hwnd,(LPCTSTR)MAKELONG(dndaware,0))) {
7745  win = (Window_t) gdk_xid_table_lookup(hwndc);
7746  if (win && win != dragwin && win != input)
7747  return win;
7748  }
7749  if (hwndc == NULL)
7750  done = TRUE;
7751  else if (hwndc == hwndt)
7752  done = TRUE;
7753  else
7754  hwndt = hwndc;
7755  if (GetProp(hwndt,(LPCTSTR)MAKELONG(dndaware,0))) {
7756  win = (Window_t) gdk_xid_table_lookup(hwndt);
7757  if (win && win != dragwin && win != input)
7758  return win;
7759  }
7760  }
7761  }
7762  hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
7763  }
7764  return kNone;
7765 }
7766 
7767 ////////////////////////////////////////////////////////////////////////////////
7768 /// Checks if Window win is DND aware, and knows any of the DND formats
7769 /// passed in argument.
7770 
7771 Bool_t TGWin32::IsDNDAware(Window_t win, Atom_t *typelist)
7772 {
7773  if (!win) return kFALSE;
7774 
7775  Atom_t version = 0;
7776  Atom_t dndaware = InternAtom("XdndAware", kFALSE);
7777  HWND window = (HWND)GDK_DRAWABLE_XID((GdkWindow *)win);
7778  while (window) {
7779  version = (Atom_t)GetProp(window,(LPCTSTR)MAKELONG(dndaware,0));
7780  if (version) return kTRUE;
7781  window = ::GetParent(window);
7782  }
7783  return kFALSE;
7784 }
7785 
7786 ////////////////////////////////////////////////////////////////////////////////
7787 /// Add XdndAware property and the list of drag and drop types to the
7788 /// Window win.
7789 
7790 void TGWin32::SetDNDAware(Window_t id, Atom_t *typelist)
7791 {
7792  int n;
7793  if (!id) return;
7794 
7795  DWORD dwStyle = GetWindowLong((HWND)GDK_DRAWABLE_XID((GdkWindow *)id),
7796  GWL_EXSTYLE);
7797  SetWindowLong((HWND)GDK_DRAWABLE_XID((GdkWindow *)id), GWL_EXSTYLE,
7798  dwStyle | WS_EX_ACCEPTFILES);
7799  Atom_t dndaware = InternAtom("XdndAware", kFALSE);
7800  SetProp((HWND)GDK_DRAWABLE_XID((GdkWindow *)id),
7801  (LPCTSTR)MAKELONG(dndaware,0),
7802  (HANDLE)XDND_PROTOCOL_VERSION);
7803 
7804  if (typelist == 0)
7805  return;
7806  for (n = 0; typelist[n]; n++);
7807  Atom_t dndtypelist = InternAtom("XdndTypeList", kFALSE);
7808  SetProp((HWND)GDK_DRAWABLE_XID((GdkWindow *)id),
7809  (LPCTSTR)MAKELONG(dndtypelist,0),
7810  (HANDLE)typelist);
7811 
7812 }
7813 
7814 ////////////////////////////////////////////////////////////////////////////////
7815 /// Set user thread id. This is used when an extra thread is created
7816 /// to process events.
7817 
7818 void TGWin32::SetUserThreadId(ULong_t id)
7819 {
7820  if (id == 0) {
7821  TGWin32ProxyBase::fgMainThreadId = ((TWinNTSystem*)gSystem)->GetGUIThreadId();
7822  }
7823  else {
7824  TGWin32ProxyBase::fgUserThreadId = id;
7825  }
7826 }
7827