0028360: Draw Harness - access for DRAW TCL interpreter needed for custom applications
[occt.git] / src / Draw / Draw_Window.cxx
1 // Created on: 1994-07-27
2 // Created by: Remi LEQUETTE
3 // Copyright (c) 1994-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 // include windows.h first to have all definitions available
18 #ifdef _WIN32
19 #include <windows.h>
20 #endif
21
22 #include <Standard_ErrorHandler.hxx>
23
24 #include <tcl.h>
25 #include <Draw_Interpretor.hxx>
26 #include <Draw_Window.hxx>
27 #include <Draw_Appli.hxx>
28 #include <TCollection_AsciiString.hxx>
29 #include <TCollection_ExtendedString.hxx>
30 #include <Image_AlienPixMap.hxx>
31 #include <NCollection_List.hxx>
32
33 extern Standard_Boolean Draw_VirtualWindows;
34 static Tcl_Interp *interp;        /* Interpreter for this application. */
35 static NCollection_List<Draw_Window::FCallbackBeforeTerminate> MyCallbacks;
36
37 void Draw_Window::AddCallbackBeforeTerminate(FCallbackBeforeTerminate theCB)
38 {
39   MyCallbacks.Append(theCB);
40 }
41
42 void Draw_Window::RemoveCallbackBeforeTerminate(FCallbackBeforeTerminate theCB)
43 {
44   NCollection_List<Draw_Window::FCallbackBeforeTerminate>::Iterator Iter(MyCallbacks);
45   for(; Iter.More(); Iter.Next())
46   {
47     if (Iter.Value() == theCB)
48     {
49       MyCallbacks.Remove(Iter);
50       break;
51     }
52   }
53 }
54
55 /*
56  *----------------------------------------------------------------------
57  *
58  * Prompt --
59  *
60  *        Issue a prompt on standard output, or invoke a script
61  *        to issue the prompt.
62  *
63  * Results:
64  *        None.
65  *
66  * Side effects:
67  *        A prompt gets output, and a Tcl script may be evaluated
68  *        in interp.
69  *
70  *----------------------------------------------------------------------
71  */
72
73 static void Prompt(Tcl_Interp *Interp, int partial)
74 {
75
76   // MKV 29.03.05
77 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
78     const char *promptCmd;
79 #else
80     char *promptCmd;
81 #endif
82     int code;
83     Tcl_Channel  outChannel, errChannel;
84     outChannel = Tcl_GetStdChannel(TCL_STDOUT);
85     promptCmd = Tcl_GetVar(Interp,(char*)
86         (partial ? "tcl_prompt2" : "tcl_prompt1"), TCL_GLOBAL_ONLY);
87
88     if (promptCmd == NULL) {
89 defaultPrompt:
90       if (!partial && outChannel) {
91         Tcl_Write(outChannel, "% ", 2);
92       }
93     } else {
94       code = Tcl_Eval(Interp, promptCmd);
95       outChannel = Tcl_GetStdChannel(TCL_STDOUT);
96       errChannel = Tcl_GetStdChannel(TCL_STDERR);
97       if (code != TCL_OK) {
98         if (errChannel) {
99 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
100           Tcl_Write(errChannel, Tcl_GetStringResult(Interp), -1);
101 #else
102           Tcl_Write(errChannel, Interp->result, -1);
103 #endif
104           Tcl_Write(errChannel, "\n", 1);
105         }
106         Tcl_AddErrorInfo(Interp,
107                          "\n    (script that generates prompt)");
108         goto defaultPrompt;
109       }
110     }
111     if (outChannel) {
112       Tcl_Flush(outChannel);
113     }
114 }
115
116 #if !defined(_WIN32) && !defined(__WIN32__)
117
118 #include <OSD_Timer.hxx>
119 #include <Draw_Window.hxx>
120 #include <unistd.h>
121
122 #if defined(__APPLE__) && !defined(MACOSX_USE_GLX)
123   // use forward declaration for small subset of used Tk functions
124   // to workaround broken standard Tk framework installation within OS X SDKs
125   // which *HAS* X11 headers in Tk.framework but doesn't install them appropriately
126   #define _TK
127   typedef struct Tk_Window_* Tk_Window;
128   typedef const char* Tk_Uid;
129
130   extern "C" int Tk_Init (Tcl_Interp* interp);
131   extern "C" void Tk_MainLoop();
132   extern "C" Tk_Window Tk_MainWindow (Tcl_Interp* interp) ;
133   extern "C" Tk_Uid Tk_GetUid (const char* str);
134   extern "C" const char* Tk_SetAppName (Tk_Window tkwin, const char* name) ;
135   extern "C" void Tk_GeometryRequest (Tk_Window tkwin, int reqWidth, int reqHeight);
136
137 #else
138   #include <tk.h>
139 #endif
140
141 /*
142  * Global variables used by the main program:
143  */
144
145 char *tcl_RcFileName = NULL;    /* Name of a user-specific startup script
146                                  * to source if the application is being run
147                                  * interactively (e.g. "~/.wishrc").  Set
148                                  * by Tcl_AppInit.  NULL means don't source
149                                  * anything ever. */
150
151 static Tcl_DString command;     /* Used to assemble lines of terminal input
152                                  * into Tcl commands. */
153 static Tcl_DString line;        /* Used to read the next line from the
154                                  * terminal input. */
155 //static char errorExitCmd[] = "exit 1";
156
157 /*
158  * Forward declarations for procedures defined later in this file:
159  */
160
161 static void StdinProc (ClientData clientData, int mask);
162
163 static void Prompt (Tcl_Interp *Interp, int partial);
164
165 static Standard_Boolean tty;        /* Non-zero means standard input is a
166                                  * terminal-like device.  Zero means it's
167                                  * a file. */
168
169 Standard_Integer Draw_WindowScreen = 0;
170 Standard_Boolean Draw_BlackBackGround = Standard_True;
171
172
173 // Initialization of static variables of Draw_Window
174 //======================================================
175 Draw_Window* Draw_Window::firstWindow = NULL;
176
177 // X11 specific part
178 #if !defined(__APPLE__) || defined(MACOSX_USE_GLX)
179 #include <X11/Xutil.h>
180 #include <Aspect_DisplayConnection.hxx>
181
182 static unsigned long thePixels[MAXCOLOR];
183
184 Display* Draw_WindowDisplay = NULL;
185 Colormap Draw_WindowColorMap;
186 static Handle(Aspect_DisplayConnection) Draw_DisplayConnection;
187
188 // Base_Window struct definition
189 //===================================
190 struct Base_Window
191 {
192   GC gc;
193   XSetWindowAttributes xswa;
194 };
195
196 //=======================================================================
197 //function : Draw_Window
198 //purpose  :
199 //=======================================================================
200 Draw_Window::Draw_Window() :
201        base(*new Base_Window()),
202        win(0),
203        myBuffer(0),
204        next(firstWindow),
205        previous(NULL),
206        myUseBuffer(Standard_False),
207        withWindowManager(Standard_True)
208 {
209   myMother = RootWindow(Draw_WindowDisplay,
210                         Draw_WindowScreen);
211
212   if (firstWindow) firstWindow->previous = this;
213   firstWindow = this;
214 }
215
216 //=======================================================================
217 //function : Draw_Window
218 //purpose  :
219 //=======================================================================
220 Draw_Window::Draw_Window(Window mother) :
221        base(*new Base_Window()),
222        win(0),
223        myBuffer(0),
224        next(firstWindow),
225        previous(NULL),
226        myUseBuffer(Standard_False),
227        withWindowManager(Standard_True)
228 {
229   myMother = mother;
230
231   if (firstWindow) firstWindow->previous = this;
232   firstWindow = this;
233 }
234
235 //=======================================================================
236 //function : Draw_Window
237 //purpose  :
238 //=======================================================================
239 Draw_Window::Draw_Window (const char* title,
240                           Standard_Integer X, Standard_Integer Y,
241                           Standard_Integer DX, Standard_Integer DY) :
242        base(*new Base_Window()),
243        win(0),
244        myBuffer(0),
245        next(firstWindow),
246        previous(NULL),
247        myUseBuffer(Standard_False),
248        withWindowManager(Standard_True)
249 {
250   myMother = RootWindow(Draw_WindowDisplay,
251                         Draw_WindowScreen);
252
253   if (firstWindow) firstWindow->previous = this;
254   firstWindow = this;
255   Init(X,Y,DX,DY);
256   SetTitle(title);
257 }
258
259 //=======================================================================
260 //function : Draw_Window
261 //purpose  :
262 //=======================================================================
263 Draw_Window::Draw_Window (const char* window ) :
264        base(*new Base_Window()),
265        win(0),
266        myBuffer(0),
267        next(firstWindow),
268        previous(NULL),
269        myUseBuffer(Standard_False),
270        withWindowManager(Standard_True)
271 {
272   sscanf(window,"%lx",&win);
273   Standard_Integer X,Y,DX,DY;
274
275   if (firstWindow) firstWindow->previous = this;
276   firstWindow = this;
277   GetPosition(X,Y);
278   DX=HeightWin();
279   DY=WidthWin();
280
281   Init(X,Y,DX,DY);
282 }
283
284 //=======================================================================
285 //function : Draw_Window
286 //purpose  :
287 //=======================================================================
288 Draw_Window::Draw_Window (Window mother,
289                           char* title,
290                           Standard_Integer X, Standard_Integer Y,
291                           Standard_Integer DX, Standard_Integer DY) :
292        base(*new Base_Window()),
293        win(0),
294        myBuffer(0),
295        next(firstWindow),
296        previous(NULL),
297        myUseBuffer(Standard_False),
298        withWindowManager(Standard_True)
299 {
300   myMother = mother;
301
302   if (firstWindow) firstWindow->previous = this;
303   firstWindow = this;
304   Init(X,Y,DX,DY);
305   SetTitle(title);
306 }
307
308 //=======================================================================
309 //function : ~Draw_Window
310 //purpose  :
311 //=======================================================================
312 Draw_Window::~Draw_Window()
313 {
314   if (previous)
315     previous->next = next;
316   else
317     firstWindow = next;
318   if (next)
319     next->previous = previous;
320
321   if (myBuffer != 0)
322   {
323     XFreePixmap(Draw_WindowDisplay, myBuffer);
324     myBuffer = 0;
325   }
326   // Liberation pointer on Base_Window
327   delete &base;
328 }
329
330 //=======================================================================
331 //function : Init
332 //purpose  :
333 //=======================================================================
334 void Draw_Window::Init(Standard_Integer X, Standard_Integer Y,
335                        Standard_Integer DX, Standard_Integer DY)
336 {
337   unsigned long setmask;
338
339   if (Draw_BlackBackGround)
340   {
341     base.xswa.background_pixel = BlackPixel(Draw_WindowDisplay,Draw_WindowScreen);
342     base.xswa.border_pixel     = WhitePixel(Draw_WindowDisplay,Draw_WindowScreen);
343   }
344   else
345   {
346     base.xswa.background_pixel = WhitePixel(Draw_WindowDisplay,Draw_WindowScreen);
347     base.xswa.border_pixel     = BlackPixel(Draw_WindowDisplay,Draw_WindowScreen);
348   }
349   base.xswa.colormap         = Draw_WindowColorMap;
350   setmask               = CWBackPixel | CWBorderPixel ;
351
352   XSizeHints myHints;
353   myHints.flags = USPosition;
354   myHints.x = (int) X;
355   myHints.y = (int) Y;
356
357   if (win == 0)
358   {
359     win = XCreateWindow(Draw_WindowDisplay,
360                         myMother,
361                         (int) X,(int) Y,
362                         (unsigned int) DX,(unsigned int) DY,
363                         5,
364                         DefaultDepth(Draw_WindowDisplay,Draw_WindowScreen),
365                         InputOutput,
366                         DefaultVisual(Draw_WindowDisplay,Draw_WindowScreen),
367                         setmask,&base.xswa);
368     XSelectInput(Draw_WindowDisplay, win, ButtonPressMask|ExposureMask|
369                                           StructureNotifyMask);
370
371     // advise to the window manager to place it where I need
372     XSetWMNormalHints(Draw_WindowDisplay,win,&myHints);
373
374     if (Draw_VirtualWindows)
375     {
376       myUseBuffer = Standard_True;
377       InitBuffer();
378     }
379   }
380
381   base.gc = XCreateGC(Draw_WindowDisplay, win, 0, NULL);
382
383   XSetPlaneMask(Draw_WindowDisplay,base.gc,AllPlanes);
384   XSetForeground(Draw_WindowDisplay,
385                  base.gc, WhitePixel(Draw_WindowDisplay,Draw_WindowScreen));
386   XSetBackground(Draw_WindowDisplay,
387                  base.gc, BlackPixel(Draw_WindowDisplay,Draw_WindowScreen));
388   // save in case of window recovery
389
390   base.xswa.backing_store = Always;
391   XChangeWindowAttributes(Draw_WindowDisplay, win,
392                           CWBackingStore, &base.xswa);
393
394   XSetLineAttributes (Draw_WindowDisplay, base.gc,
395                       0, LineSolid, CapButt, JoinMiter);
396 }
397
398 //=======================================================================
399 //function : InitBuffer
400 //purpose  :
401 //=======================================================================
402 void Draw_Window::InitBuffer()
403 {
404   if (myUseBuffer) {
405     if (myBuffer != 0) {
406       XFreePixmap (Draw_WindowDisplay, myBuffer);
407     }
408     XWindowAttributes winAttr;
409     XGetWindowAttributes (Draw_WindowDisplay, win, &winAttr);
410     myBuffer = XCreatePixmap (Draw_WindowDisplay, win, winAttr.width, winAttr.height, winAttr.depth);
411   }
412   else if (myBuffer != 0)
413   {
414     XFreePixmap (Draw_WindowDisplay, myBuffer);
415     myBuffer = 0;
416   }
417 }
418
419 //=======================================================================
420 //function : StopWinManager
421 //purpose  :
422 //=======================================================================
423 void Draw_Window::StopWinManager()
424 {
425 //  XGCValues winGc;
426   XWindowAttributes winAttr;
427   XGetWindowAttributes (Draw_WindowDisplay, win, &winAttr);
428   Destroy();
429
430   XSizeHints myHints;
431   myHints.flags = USPosition;
432   myHints.x = (int) 30;
433   myHints.y = (int) 100;
434
435   base.xswa.override_redirect = 1;
436   base.xswa.border_pixel = BlackPixel(Draw_WindowDisplay,
437                                  Draw_WindowScreen);
438   base.xswa.background_pixel = WhitePixel(Draw_WindowDisplay,
439                                Draw_WindowScreen);
440
441   withWindowManager = Standard_False;
442
443   win = XCreateWindow(Draw_WindowDisplay, myMother,
444                       winAttr.x, winAttr.y,
445                       winAttr.width, winAttr.height,
446                       2,
447                       CopyFromParent, InputOutput, CopyFromParent,
448                       CWBorderPixel|CWOverrideRedirect|CWBackPixel, &base.xswa);
449
450
451   // adwise to the window manager to place it where I wish
452   XSetWMNormalHints(Draw_WindowDisplay,win,&myHints);
453
454   // all masks of the old window are reassigned to the new one.
455   XSelectInput(Draw_WindowDisplay,win,winAttr.your_event_mask);
456 }
457
458 //=======================================================================
459 //function : SetPosition
460 //purpose  :
461 //=======================================================================
462 void Draw_Window::SetPosition(Standard_Integer NewXpos,
463                               Standard_Integer NewYpos)
464 {
465   Standard_Integer x,y;
466   GetPosition(x, y);
467
468   if ( (x != NewXpos) || (y != NewYpos) )
469     XMoveWindow(Draw_WindowDisplay, win, NewXpos, NewYpos);
470 }
471
472 //=======================================================================
473 //function : SetDimension
474 //purpose  :
475 //=======================================================================
476 void Draw_Window::SetDimension(Standard_Integer NewDx,
477                                Standard_Integer NewDy)
478 {
479   if ( (NewDx != WidthWin() ) || (NewDy != HeightWin() ) )
480     XResizeWindow(Draw_WindowDisplay, win, NewDx, NewDy);
481 }
482
483 //=======================================================================
484 //function : GetPosition
485 //purpose  :
486 //=======================================================================
487 void Draw_Window::GetPosition(Standard_Integer &PosX,
488                               Standard_Integer &PosY)
489 {
490   XWindowAttributes winAttr;
491   XGetWindowAttributes(Draw_WindowDisplay, win, &winAttr);
492
493   PosX = winAttr.x;
494   PosY = winAttr.y;
495 }
496
497 //=======================================================================
498 //function : HeightWin
499 //purpose  :
500 //=======================================================================
501 Standard_Integer Draw_Window::HeightWin() const
502 {
503   Standard_Integer DY;
504   XWindowAttributes winAttr;
505   XGetWindowAttributes(Draw_WindowDisplay, win, &winAttr);
506
507   DY = winAttr.height;
508   return DY;
509 }
510
511 //=======================================================================
512 //function : WidthWin
513 //purpose  :
514 //=======================================================================
515 Standard_Integer Draw_Window::WidthWin() const
516 {
517   Standard_Integer DX;
518   XWindowAttributes winAttr;
519   XGetWindowAttributes(Draw_WindowDisplay, win, &winAttr);
520
521   DX = winAttr.width;
522   return DX;
523 }
524
525 //=======================================================================
526 //function : SetTitle
527 //purpose  :
528 //=======================================================================
529 void Draw_Window::SetTitle(const TCollection_AsciiString& theTitle)
530 {
531   XStoreName (Draw_WindowDisplay, win, theTitle.ToCString());
532 }
533
534 //=======================================================================
535 //function : GetTitle
536 //purpose  :
537 //=======================================================================
538 TCollection_AsciiString Draw_Window::GetTitle() const
539 {
540   char* aTitle = NULL;
541   XFetchName (Draw_WindowDisplay, win, &aTitle);
542   return TCollection_AsciiString (aTitle);
543 }
544
545 //=======================================================================
546 //function : GetDrawable
547 //purpose  :
548 //=======================================================================
549 Drawable Draw_Window::GetDrawable() const
550 {
551   return myUseBuffer ? myBuffer : win;
552 }
553
554 //=======================================================================
555 //function :DefineColor
556 //purpose  :
557 //=======================================================================
558 Standard_Boolean Draw_Window::DefineColor(const Standard_Integer i, const char* colorName)
559 {
560   XColor color;
561
562   if (!XParseColor(Draw_WindowDisplay,Draw_WindowColorMap,colorName,&color))
563     return Standard_False;
564   if (!XAllocColor(Draw_WindowDisplay,Draw_WindowColorMap,&color))
565     return Standard_False;
566   thePixels[i % MAXCOLOR] = color.pixel;
567   return Standard_True;
568 }
569
570 //=======================================================================
571 //function : DisplayWindow
572 //purpose  :
573 //=======================================================================
574 void Draw_Window::DisplayWindow()
575 {
576   if (Draw_VirtualWindows)
577   {
578     return;
579   }
580   else
581   {
582     XMapRaised(Draw_WindowDisplay, win);
583   }
584   XFlush(Draw_WindowDisplay);
585 }
586
587 //=======================================================================
588 //function : Hide
589 //purpose  :
590 //=======================================================================
591 void Draw_Window::Hide()
592 {
593    XUnmapWindow(Draw_WindowDisplay, win);
594 }
595
596 //=======================================================================
597 //function : Destroy
598 //purpose  :
599 //=======================================================================
600 void Draw_Window::Destroy()
601 {
602   XFreeGC (Draw_WindowDisplay, base.gc);
603   XDestroyWindow(Draw_WindowDisplay, win);
604   win = 0;
605   if (myBuffer != 0)
606   {
607     XFreePixmap(Draw_WindowDisplay, myBuffer);
608     myBuffer = 0;
609   }
610 }
611
612 //=======================================================================
613 //function : Clear
614 //purpose  :
615 //=======================================================================
616 void Draw_Window::Clear()
617 {
618   if (myUseBuffer)
619   {
620     // XClearArea only applicable for windows
621     XGCValues currValues;
622     XGetGCValues(Draw_WindowDisplay, base.gc, GCBackground | GCForeground, &currValues);
623     XSetForeground(Draw_WindowDisplay, base.gc, currValues.background);
624     XFillRectangle(Draw_WindowDisplay, myBuffer, base.gc, 0, 0, WidthWin(), HeightWin());
625     XSetForeground(Draw_WindowDisplay, base.gc, currValues.foreground);
626   }
627   else
628   {
629     XClearArea(Draw_WindowDisplay, win, 0, 0, 0, 0, False);
630   }
631 }
632
633 //=======================================================================
634 //function : Flush
635 //purpose  :
636 //=======================================================================
637 void Draw_Window::Flush()
638 {
639   XFlush(Draw_WindowDisplay);
640 }
641
642 //=======================================================================
643 //function : DrawString
644 //purpose  :
645 //=======================================================================
646 void Draw_Window::DrawString(int X, int Y, char *text)
647 {
648   XDrawString(Draw_WindowDisplay, GetDrawable(), base.gc, X, Y, text, strlen(text));
649 }
650
651 //=======================================================================
652 //function : DrawSegments
653 //purpose  :
654 //=======================================================================
655 void Draw_Window::DrawSegments(Segment *tab, int nbElem)
656 {
657   XDrawSegments(Draw_WindowDisplay, GetDrawable(), base.gc, (XSegment*) tab, nbElem);
658 }
659
660 //=======================================================================
661 //function : Redraw
662 //purpose  :
663 //=======================================================================
664 void Draw_Window::Redraw()
665 {
666   if (myUseBuffer) {
667     XCopyArea (Draw_WindowDisplay,
668                myBuffer, win, // source, destination Drawables
669                base.gc,
670                0, 0,  // source x, y
671                WidthWin(), HeightWin(),
672                0, 0); // destination x, y
673   }
674 }
675
676 //=======================================================================
677 //function : SetColor
678 //purpose  :
679 //=======================================================================
680 void Draw_Window::SetColor(Standard_Integer color)
681 {
682   XSetForeground(Draw_WindowDisplay, base.gc, thePixels[color]);
683 }
684
685 //=======================================================================
686 //function : SetMode
687 //purpose  :
688 //=======================================================================
689 void Draw_Window::SetMode( int mode)
690 {
691   XSetFunction(Draw_WindowDisplay, base.gc, mode);
692 }
693
694 //=======================================================================
695 //function : Save
696 //purpose  :
697 //=======================================================================
698 Standard_Boolean Draw_Window::Save (const char* theFileName) const
699 {
700   // make sure all draw operations done
701   XSync (Draw_WindowDisplay, True);
702
703   // the attributes
704   XWindowAttributes winAttr;
705   XGetWindowAttributes (Draw_WindowDisplay, win, &winAttr);
706
707   if (!myUseBuffer)
708   {
709     // make sure that the whole window fit on display to prevent BadMatch error
710     XWindowAttributes winAttrRoot;
711     XGetWindowAttributes (Draw_WindowDisplay, XRootWindowOfScreen (winAttr.screen), &winAttrRoot);
712
713     Window winChildDummy;
714     int winLeft = 0;
715     int winTop = 0;
716     XTranslateCoordinates (Draw_WindowDisplay, win, XRootWindowOfScreen (winAttr.screen),
717                            0, 0, &winLeft, &winTop, &winChildDummy);
718
719     if (((winLeft + winAttr.width) > winAttrRoot.width)  || winLeft < winAttrRoot.x ||
720         ((winTop + winAttr.height) > winAttrRoot.height) || winTop  < winAttrRoot.y)
721     {
722       std::cerr << "The window not fully visible! Can't create the snapshot.\n";
723       return Standard_False;
724     }
725   }
726
727   XVisualInfo aVInfo;
728   if (XMatchVisualInfo (Draw_WindowDisplay, Draw_WindowScreen, 32, TrueColor, &aVInfo) == 0
729    && XMatchVisualInfo (Draw_WindowDisplay, Draw_WindowScreen, 24, TrueColor, &aVInfo) == 0)
730   {
731     std::cerr << "24-bit TrueColor visual is not supported by server!\n";
732     return Standard_False;
733   }
734
735   Image_AlienPixMap anImage;
736   bool isBigEndian = Image_PixMap::IsBigEndianHost();
737   const Standard_Size aSizeRowBytes = Standard_Size(winAttr.width) * 4;
738   if (!anImage.InitTrash (isBigEndian ? Image_PixMap::ImgRGB32 : Image_PixMap::ImgBGR32,
739                           Standard_Size(winAttr.width), Standard_Size(winAttr.height), aSizeRowBytes))
740   {
741     return Standard_False;
742   }
743   anImage.SetTopDown (true);
744
745   XImage* anXImage = XCreateImage (Draw_WindowDisplay, aVInfo.visual,
746                                    32, ZPixmap, 0, (char* )anImage.ChangeData(), winAttr.width, winAttr.height, 32, int(aSizeRowBytes));
747   anXImage->bitmap_bit_order = anXImage->byte_order = (isBigEndian ? MSBFirst : LSBFirst);
748   if (XGetSubImage (Draw_WindowDisplay, GetDrawable(),
749                     0, 0, winAttr.width, winAttr.height,
750                     AllPlanes, ZPixmap, anXImage, 0, 0) == NULL)
751   {
752     anXImage->data = NULL;
753     XDestroyImage (anXImage);
754     return Standard_False;
755   }
756
757   // destroy the image
758   anXImage->data = NULL;
759   XDestroyImage (anXImage);
760
761   // save the image
762   return anImage.Save (theFileName);
763 }
764
765 //=======================================================================
766 //function : Wait
767 //purpose  :
768 //=======================================================================
769
770 void Draw_Window::Wait (Standard_Boolean wait)
771 {
772   Flush();
773   if (!wait) {
774     XSelectInput(Draw_WindowDisplay,win,
775                  ButtonPressMask|ExposureMask | StructureNotifyMask |
776                  PointerMotionMask);
777   }
778   else {
779     XSelectInput(Draw_WindowDisplay,win,
780                  ButtonPressMask|ExposureMask | StructureNotifyMask);
781   }
782 }
783
784 //=======================================================================
785 //function : ProcessEvent
786 //purpose  :
787 //=======================================================================
788
789 void ProcessEvent(Draw_Window& win, XEvent& xev)
790 {
791   Standard_Integer X,Y,button;
792   KeySym keysym;
793   XComposeStatus stat;
794   char chainekey[10];
795
796
797   switch (xev.type) {
798
799   case Expose :
800     win.WExpose();
801     break;
802
803   case ButtonPress :
804     X = xev.xbutton.x;
805     Y = xev.xbutton.y;
806     button = xev.xbutton.button;
807     win.WButtonPress(X,Y,button);
808     break;
809
810   case ButtonRelease :
811     X = xev.xbutton.x;
812     Y = xev.xbutton.y;
813     button = xev.xbutton.button;
814     win.WButtonRelease(X,Y,button);
815     break;
816
817   case KeyPress :
818     XLookupString(&(xev.xkey),
819                          chainekey,
820                          10,
821                          &keysym,
822                          &stat);
823     break;
824
825   case MotionNotify :
826     X = xev.xmotion.x;
827     Y = xev.xmotion.y;
828     win.WMotionNotify(X,Y);
829     break;
830
831   case ConfigureNotify :
832     if (win.withWindowManager)
833       win.WConfigureNotify(xev.xconfigure.x, xev.xconfigure.y,
834                            xev.xconfigure.width,
835                            xev.xconfigure.height);
836     break;
837
838   case UnmapNotify :
839
840     win.WUnmapNotify();
841     break;
842   }
843 }
844
845 //=======================================================================
846 //function : WExpose
847 //purpose  :
848 //=======================================================================
849 void Draw_Window::WExpose()
850 {
851 }
852
853 //=======================================================================
854 //function : WButtonPress
855 //purpose  :
856 //=======================================================================
857 void Draw_Window::WButtonPress(const Standard_Integer,
858                                const Standard_Integer,
859                                const Standard_Integer&)
860 {
861 }
862
863 //=======================================================================
864 //function : WButtonRelease
865 //purpose  :
866 //=======================================================================
867 void Draw_Window::WButtonRelease(const Standard_Integer,
868                                  const Standard_Integer,
869                                  const Standard_Integer&)
870 {
871 }
872
873 /**************************
874 //=======================================================================
875 //function : WKeyPress
876 //purpose  :
877 //=======================================================================
878
879 void Draw_Window::WKeyPress(char, KeySym&)
880 {
881 }
882 ***************************/
883
884 //=======================================================================
885 //function : WMotionNotify
886 //purpose  :
887 //=======================================================================
888 void Draw_Window::WMotionNotify(const Standard_Integer ,
889                                 const Standard_Integer )
890 {
891 }
892
893 //=======================================================================
894 //function : WConfigureNotify
895 //purpose  :
896 //=======================================================================
897
898 void Draw_Window::WConfigureNotify(const Standard_Integer,
899                                    const Standard_Integer,
900                                    const Standard_Integer,
901                                    const Standard_Integer)
902 {
903 }
904
905 //=======================================================================
906 //function : WUnmapNotify
907 //purpose  :
908 //=======================================================================
909
910 void Draw_Window::WUnmapNotify()
911 {
912 }
913
914
915 //======================================================
916 // funtion : ProcessEvents
917 // purpose : process pending X events
918 //======================================================
919
920 static void ProcessEvents(ClientData,int)
921 {
922   // test for X Event
923
924   while (XPending(Draw_WindowDisplay)) {
925
926     XEvent xev;
927     xev.type = 0;
928
929     XNextEvent(Draw_WindowDisplay,&xev);
930
931     /* search the window in the window list */
932     Draw_Window* w = Draw_Window::firstWindow;
933     Standard_Integer found=0;
934     while (w) {
935       if (xev.xany.window == w->win) {
936         ProcessEvent(*w, xev);
937         found=1;
938         break;
939       }
940       w = w->next;
941     }
942     if (found==0) {
943       Tk_HandleEvent(&xev);
944     }
945   }
946 }
947
948 //======================================================
949 // funtion : GetNextEvent()
950 // purpose :
951 //======================================================
952 void GetNextEvent(Event& ev)
953 {
954   XEvent xev;
955   XNextEvent(Draw_WindowDisplay, &xev);
956   switch(xev.type)
957   {
958     case ButtonPress :
959       ev.type = 4;
960       ev.window = xev.xbutton.window;
961       ev.button = xev.xbutton.button;
962       ev.x = xev.xbutton.x;
963       ev.y = xev.xbutton.y;
964       break;
965
966     case MotionNotify :
967       ev.type = 6;
968       ev.window = xev.xmotion.window;
969       ev.button = 0;
970       ev.x = xev.xmotion.x;
971       ev.y = xev.xmotion.y;
972       break;
973   }
974 }
975 #endif //__APPLE__
976
977 //======================================================
978 // funtion :Run_Appli
979 // purpose :
980 //======================================================
981
982
983 static Standard_Boolean(*Interprete) (const char*);
984
985 void Run_Appli(Standard_Boolean (*interprete) (const char*))
986 {
987   Tcl_Channel outChannel, inChannel ;
988   Interprete = interprete;
989
990 #ifdef _TK
991
992     /*
993      * Commands will come from standard input, so set up an event
994      * handler for standard input.  If the input device is aEvaluate the
995      * .rc file, if one has been specified, set up an event handler
996      * for standard input, and print a prompt if the input
997      * device is a terminal.
998      */
999   inChannel = Tcl_GetStdChannel(TCL_STDIN);
1000   if (inChannel) {
1001             Tcl_CreateChannelHandler(inChannel, TCL_READABLE, StdinProc,
1002                     (ClientData) inChannel);
1003         }
1004
1005   // Create a handler for the draw display
1006
1007   // Adding of the casting into void* to be able to compile on AO1
1008   // ConnectionNumber(Draw_WindowDisplay) is an int 32 bits
1009   //                    (void*) is a pointer      64 bits ???????
1010
1011 #if !defined(__APPLE__) || defined(MACOSX_USE_GLX)
1012 #if TCL_MAJOR_VERSION  < 8
1013     Tk_CreateFileHandler((void*) ConnectionNumber(Draw_WindowDisplay),
1014                          TK_READABLE, ProcessEvents,(ClientData) 0 );
1015 #else
1016     Tk_CreateFileHandler(ConnectionNumber(Draw_WindowDisplay),
1017                          TK_READABLE, ProcessEvents,(ClientData) 0 );
1018 #endif
1019 #endif // __APPLE__
1020
1021 #endif
1022
1023   Draw_Interpretor& aCommands = Draw::GetInterpretor();
1024
1025   if (tty) Prompt(aCommands.Interp(), 0);
1026   Prompt(aCommands.Interp(), 0);
1027
1028   outChannel = Tcl_GetStdChannel(TCL_STDOUT);
1029   if (outChannel) {
1030         Tcl_Flush(outChannel);
1031     }
1032   Tcl_DStringInit(&command);
1033
1034   /*
1035    * Loop infinitely, waiting for commands to execute.  When there
1036    * are no windows left, Tk_MainLoop returns and we exit.
1037    */
1038
1039 #ifdef _TK
1040
1041   if (Draw_VirtualWindows) {
1042     // main window will never shown
1043     // but main loop will parse all Xlib messages
1044     Tcl_Eval(aCommands.Interp(), "wm withdraw .");
1045   }
1046   Tk_MainLoop();
1047
1048 #else
1049
1050   fd_set readset;
1051   Standard_Integer count = ConnectionNumber(Draw_WindowDisplay);
1052   Standard_Integer numfd;
1053   while (1) {
1054       FD_ZERO(&readset);
1055       FD_SET(0,&readset);
1056       FD_SET(count,&readset);
1057 #ifdef HPUX
1058       numfd = select(count+1,(Integer*)&readset,NULL,NULL,NULL);
1059 #else
1060       numfd = select(count+1,&readset,NULL,NULL,NULL);
1061 #endif
1062       if (FD_ISSET(0,&readset))     StdinProc((ClientData)0,0);
1063       if (FD_ISSET(count,&readset)) ProcessEvents((ClientData)0,0);
1064     }
1065
1066 #endif
1067   NCollection_List<Draw_Window::FCallbackBeforeTerminate>::Iterator Iter(MyCallbacks);
1068   for(; Iter.More(); Iter.Next())
1069   {
1070       (*Iter.Value())();
1071   }
1072 }
1073
1074 //======================================================
1075 // funtion : Init_Appli()
1076 // purpose :
1077 //======================================================
1078 Standard_Boolean Init_Appli()
1079 {
1080   Draw_Interpretor& aCommands = Draw::GetInterpretor();
1081   aCommands.Init();
1082   interp = aCommands.Interp();
1083
1084   Tcl_Init(interp) ;
1085   try {
1086     OCC_CATCH_SIGNALS
1087     Tk_Init(interp) ;
1088   } catch  (Standard_Failure) {
1089     cout <<" Pb au lancement de TK_Init "<<endl;
1090   }
1091
1092   Tcl_StaticPackage(interp, "Tk", Tk_Init, (Tcl_PackageInitProc *) NULL);
1093
1094   Tk_Window aMainWindow = Tk_MainWindow(interp) ;
1095   if (aMainWindow == NULL) {
1096 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
1097     fprintf(stderr, "%s\n", Tcl_GetStringResult(interp));
1098 #else
1099     fprintf(stderr, "%s\n", interp->result);
1100 #endif
1101     exit(1);
1102   }
1103 #if defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1104   Tk_SetAppName(aMainWindow, "Draw");
1105 #else
1106   Tk_Name(aMainWindow) = Tk_GetUid(Tk_SetAppName(aMainWindow, "Draw"));
1107 #endif
1108
1109   Tk_GeometryRequest (aMainWindow, 200, 200);
1110
1111 #if !defined(__APPLE__) || defined(MACOSX_USE_GLX)
1112   if (Draw_DisplayConnection.IsNull())
1113   {
1114     try
1115     {
1116       Draw_DisplayConnection = new Aspect_DisplayConnection();
1117     }
1118     catch (Standard_Failure)
1119     {
1120       std::cout << "Cannot open display. Interpret commands in batch mode." << std::endl;
1121       return Standard_False;
1122     }
1123   }
1124   if (Draw_WindowDisplay == NULL)
1125   {
1126     Draw_WindowDisplay = Draw_DisplayConnection->GetDisplay();
1127   }
1128   //
1129   // synchronize the display server : could be done within Tk_Init
1130   //
1131   XSynchronize(Draw_WindowDisplay, True);
1132   XSetInputFocus(Draw_WindowDisplay,
1133                  PointerRoot,
1134                  RevertToPointerRoot,
1135                  CurrentTime);
1136
1137   Draw_WindowScreen   = DefaultScreen(Draw_WindowDisplay);
1138   Draw_WindowColorMap = DefaultColormap(Draw_WindowDisplay,
1139                                         Draw_WindowScreen);
1140 #endif // __APPLE__
1141
1142   tty = isatty(0);
1143   Tcl_SetVar(interp,"tcl_interactive",(char*)(tty ? "1" : "0"), TCL_GLOBAL_ONLY);
1144 //  Tcl_SetVar(interp,"tcl_interactive",tty ? "1" : "0", TCL_GLOBAL_ONLY);
1145   return Standard_True;
1146 }
1147
1148 //======================================================
1149 // funtion : Destroy_Appli()
1150 // purpose :
1151 //======================================================
1152 void Destroy_Appli()
1153 {
1154   //XCloseDisplay(Draw_WindowDisplay);
1155 }
1156
1157 /*
1158  *----------------------------------------------------------------------
1159  *
1160  * StdinProc --
1161  *
1162  *        This procedure is invoked by the event dispatcher whenever
1163  *        standard input becomes readable.  It grabs the next line of
1164  *        input characters, adds them to a command being assembled, and
1165  *        executes the command if it's complete.
1166  *
1167  * Results:
1168  *        None.
1169  *
1170  * Side effects:
1171  *        Could be almost arbitrary, depending on the command that's
1172  *        typed.
1173  *
1174  *----------------------------------------------------------------------
1175  */
1176
1177     /* ARGSUSED */
1178 //static void StdinProc(ClientData clientData, int mask)
1179 static void StdinProc(ClientData clientData, int )
1180 {
1181   static int gotPartial = 0;
1182   char *cmd;
1183 //  int code, count;
1184   int count;
1185   Tcl_Channel chan = (Tcl_Channel) clientData;
1186
1187   // MSV Nov 2, 2001: patch for TCL 8.3: initialize line to avoid exception
1188   //                  when first user input is an empty string
1189   Tcl_DStringFree(&line);
1190   count = Tcl_Gets(chan, &line);
1191
1192   // MKV 26.05.05
1193 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)))
1194   Tcl_DString linetmp;
1195   Tcl_DStringInit(&linetmp);
1196   Tcl_UniChar * UniCharString;
1197   UniCharString = Tcl_UtfToUniCharDString(Tcl_DStringValue(&line),-1,&linetmp);
1198   Standard_Integer l = Tcl_UniCharLen(UniCharString);
1199   TCollection_AsciiString AsciiString("");
1200   Standard_Character Character;
1201   Standard_Integer i;
1202   for (i=0; i<l; i++) {
1203     Character = UniCharString[i];
1204     AsciiString.AssignCat(Character);
1205   }
1206   Tcl_DStringInit(&line);
1207   Tcl_DStringAppend(&line, AsciiString.ToCString(), -1);
1208 #endif
1209   if (count < 0) {
1210     if (!gotPartial) {
1211       if (tty) {
1212         Tcl_Exit(0);
1213       } else {
1214         Tcl_DeleteChannelHandler(chan, StdinProc, (ClientData) chan);
1215       }
1216       return;
1217     } else {
1218       count = 0;
1219     }
1220   }
1221
1222   (void) Tcl_DStringAppend(&command, Tcl_DStringValue(&line), -1);
1223   cmd = Tcl_DStringAppend(&command, "\n", -1);
1224   Tcl_DStringFree(&line);
1225   try {
1226     OCC_CATCH_SIGNALS
1227   if (!Tcl_CommandComplete(cmd)) {
1228     gotPartial = 1;
1229     goto prompt;
1230   }
1231   gotPartial = 0;
1232
1233   /*
1234    * Disable the stdin channel handler while evaluating the command;
1235    * otherwise if the command re-enters the event loop we might
1236    * process commands from stdin before the current command is
1237    * finished.  Among other things, this will trash the text of the
1238    * command being evaluated.
1239    */
1240
1241   Tcl_CreateChannelHandler(chan, 0, StdinProc, (ClientData) chan);
1242
1243
1244   /*
1245    * Disable the stdin file handler while evaluating the command;
1246    * otherwise if the command re-enters the event loop we might
1247    * process commands from stdin before the current command is
1248    * finished.  Among other things, this will trash the text of the
1249    * command being evaluated.
1250    */
1251
1252 #ifdef _TK
1253    //  Tk_CreateFileHandler(0, 0, StdinProc, (ClientData) 0);
1254 #endif
1255     //
1256     // xab average to avoid an output SIGBUS of DRAW
1257     // to ultimately prescise or remove once
1258     // the problem of free on the global variable at the average
1259     //
1260     //
1261
1262   Interprete(cmd);
1263
1264
1265   Tcl_CreateChannelHandler(chan, TCL_READABLE, StdinProc,
1266                            (ClientData) chan);
1267   Tcl_DStringFree(&command);
1268
1269   /*
1270    * Output a prompt.
1271    */
1272
1273 prompt:
1274   if (tty) Prompt(interp, gotPartial);
1275
1276  } catch (Standard_Failure) {}
1277
1278 }
1279
1280 #else
1281
1282 // Source Specifique WNT
1283
1284 /****************************************************\
1285 *  Draw_Window.cxx :
1286 *
1287 \****************************************************/
1288
1289 #include "Draw_Window.hxx"
1290 #include "DrawRessource.h"
1291 #include "init.h"
1292
1293 #include <Draw_Appli.hxx>
1294 #include <OSD.hxx>
1295
1296 #include <tk.h>
1297
1298 #define PENWIDTH 1
1299 #define CLIENTWND 0
1300 // Position of information in the extra memory
1301
1302 // indicates SUBSYSTEM:CONSOLE linker option, to be set to True in main()
1303 Standard_EXPORT
1304 Standard_Boolean Draw_IsConsoleSubsystem = Standard_False;
1305
1306
1307 Standard_Boolean Draw_BlackBackGround = Standard_True;
1308
1309 // Creation of color stylos
1310 HPEN colorPenTab[MAXCOLOR] = {CreatePen(PS_SOLID, PENWIDTH, RGB(255,255,255)),
1311                               CreatePen(PS_SOLID, PENWIDTH, RGB(255,0,0)),
1312                               CreatePen(PS_SOLID, PENWIDTH, RGB(0,255,0)),
1313                               CreatePen(PS_SOLID, PENWIDTH, RGB(0,0,255)),
1314                               CreatePen(PS_SOLID, PENWIDTH, RGB(0,255,255)),
1315                               CreatePen(PS_SOLID, PENWIDTH, RGB(255,215,0)),
1316                               CreatePen(PS_SOLID, PENWIDTH, RGB(255,0,255)),
1317                               CreatePen(PS_SOLID, PENWIDTH, RGB(255,52,179)),
1318                               CreatePen(PS_SOLID, PENWIDTH, RGB(255,165,0)),
1319                               CreatePen(PS_SOLID, PENWIDTH, RGB(255,228,225)),
1320                               CreatePen(PS_SOLID, PENWIDTH, RGB(255,160,122)),
1321                               CreatePen(PS_SOLID, PENWIDTH, RGB(199,21,133)),
1322                               CreatePen(PS_SOLID, PENWIDTH, RGB(255,255,0)),
1323                               CreatePen(PS_SOLID, PENWIDTH, RGB(240,230,140)),
1324                               CreatePen(PS_SOLID, PENWIDTH, RGB(255,127,80))};
1325
1326 // Correspondance mode X11 and WINDOWS NT
1327 int modeTab[16] = {R2_BLACK, R2_MASKPEN, R2_MASKPENNOT, R2_COPYPEN,
1328                    R2_MASKNOTPEN, R2_NOP, R2_XORPEN, R2_MERGEPEN,
1329                    R2_NOTMASKPEN, R2_NOTXORPEN, R2_NOT, R2_MERGEPENNOT,
1330                    R2_NOTCOPYPEN, R2_MERGENOTPEN, R2_NOTMERGEPEN, R2_WHITE};
1331
1332 /*--------------------------------------------------------*\
1333 |  CREATE DRAW WINDOW PROCEDURE
1334 \*--------------------------------------------------------*/
1335 HWND DrawWindow::CreateDrawWindow(HWND hWndClient, int nitem)
1336 {
1337   if (Draw_IsConsoleSubsystem) {
1338     HWND aWin = CreateWindowW (DRAWCLASS, DRAWTITLE,
1339                               WS_OVERLAPPEDWINDOW,
1340                               1,1,1,1,
1341                               NULL, NULL,::GetModuleHandle(NULL), NULL);
1342     if (!Draw_VirtualWindows)
1343     {
1344       SetWindowPos(aWin, HWND_TOPMOST, 1,1,1,1, SWP_NOMOVE);
1345       SetWindowPos(aWin, HWND_NOTOPMOST, 1,1,1,1, SWP_NOMOVE);
1346     }
1347     return aWin;
1348   }
1349   else {
1350     HANDLE hInstance = (HANDLE )GetWindowLongPtrW (hWndClient, GWLP_HINSTANCE);
1351
1352     return CreateMDIWindowW(DRAWCLASS, DRAWTITLE,
1353                            WS_CAPTION | WS_CHILD | WS_THICKFRAME,
1354                            1,1,0,0,
1355                            hWndClient, (HINSTANCE)hInstance, nitem);
1356   }
1357 }
1358
1359
1360 /*--------------------------------------------------------*\
1361 |  DRAW WINDOW PROCEDURE
1362 \*--------------------------------------------------------*/
1363 LRESULT APIENTRY DrawWindow::DrawProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
1364 {
1365   DrawWindow* localObjet = (DrawWindow* )GetWindowLongPtrW (hWnd, CLIENTWND);
1366   if (!localObjet)
1367   {
1368     return Draw_IsConsoleSubsystem
1369          ? DefWindowProcW   (hWnd, wMsg, wParam, lParam)
1370          : DefMDIChildProcW (hWnd, wMsg, wParam, lParam);
1371   }
1372
1373   switch (wMsg)
1374   {
1375     case WM_PAINT:
1376     {
1377       PAINTSTRUCT ps;
1378       BeginPaint (hWnd, &ps);
1379       if (localObjet->GetUseBuffer())
1380       {
1381         localObjet->Redraw();
1382       }
1383       else
1384       {
1385         localObjet->WExpose();
1386       }
1387       EndPaint (hWnd, &ps);
1388       return 0;
1389     }
1390     case WM_SIZE:
1391     {
1392       if (localObjet->GetUseBuffer())
1393       {
1394         localObjet->InitBuffer();
1395         localObjet->WExpose();
1396         localObjet->Redraw();
1397         return 0;
1398       }
1399       break;
1400     }
1401   }
1402   return Draw_IsConsoleSubsystem
1403        ? DefWindowProcW   (hWnd, wMsg, wParam, lParam)
1404        : DefMDIChildProcW (hWnd, wMsg, wParam, lParam);
1405 }
1406
1407
1408
1409 /*
1410 **  IMPLEMENTATION of the CLASS DRAWWINDOW
1411  */
1412
1413 /*--------------------------------------------------------*\
1414 | Initialization of static variables of DrawWindow
1415 \*--------------------------------------------------------*/
1416
1417 DrawWindow* DrawWindow::firstWindow = NULL;
1418 HWND DrawWindow::hWndClientMDI = 0;
1419
1420 /*--------------------------------------------------------*\
1421 | Constructors of Draw_Window
1422 \*--------------------------------------------------------*/
1423
1424 // Default Constructor
1425 //________________________
1426 DrawWindow::DrawWindow() :
1427         win(0),
1428         next(firstWindow),
1429         previous(NULL),
1430         myMemHbm(NULL),
1431         myUseBuffer(Standard_False)
1432 {
1433   if (firstWindow) firstWindow->previous = this;
1434   firstWindow = this;
1435 }
1436
1437 //________________________
1438 DrawWindow::DrawWindow(const char* title,
1439                        Standard_Integer X, Standard_Integer Y,
1440                        Standard_Integer dX,Standard_Integer dY) :
1441        win(0),        next(firstWindow), previous(NULL), myMemHbm(NULL), myUseBuffer(Standard_False)
1442 {
1443   if (firstWindow) firstWindow->previous = this;
1444   firstWindow = this;
1445   Init(X, Y, dX, dY);
1446   SetTitle(title);
1447 }
1448 DrawWindow::DrawWindow(const char* title,
1449                        Standard_Integer X, Standard_Integer Y,
1450                        Standard_Integer dX,Standard_Integer dY,
1451                        HWND theWin) :
1452        win(theWin),next(firstWindow), previous(NULL), myMemHbm(NULL), myUseBuffer(Standard_False)
1453 {
1454   if (firstWindow) firstWindow->previous = this;
1455   firstWindow = this;
1456   Init(X, Y, dX, dY);
1457   SetTitle(title);
1458 }
1459
1460
1461
1462 /*--------------------------------------------------------*\
1463 | Destructor of DrawWindow
1464 \*--------------------------------------------------------*/
1465 DrawWindow::~DrawWindow()
1466 {
1467   if (previous)
1468     previous->next = next;
1469   else
1470     firstWindow = next;
1471   if (next)
1472     next->previous = previous;
1473
1474   // Delete 'off-screen drawing'-related objects
1475   if (myMemHbm) {
1476     DeleteObject(myMemHbm);
1477     myMemHbm = NULL;
1478   }
1479 }
1480
1481
1482
1483 /*--------------------------------------------------------*\
1484 |  Init
1485 \*--------------------------------------------------------*/
1486 void DrawWindow::Init(Standard_Integer theXLeft, Standard_Integer theYTop,
1487                       Standard_Integer theWidth, Standard_Integer theHeight)
1488 {
1489   if (win == NULL)
1490   {
1491     win = CreateDrawWindow(hWndClientMDI, 0);
1492   }
1493
1494   // include decorations in the window dimensions
1495   // to reproduce same behaviour of Xlib window.
1496   DWORD aWinStyle   = GetWindowLongW (win, GWL_STYLE);
1497   DWORD aWinStyleEx = GetWindowLongW (win, GWL_EXSTYLE);
1498   HMENU aMenu       = GetMenu (win);
1499
1500   RECT aRect;
1501   aRect.top    = theYTop;
1502   aRect.bottom = theYTop + theHeight;
1503   aRect.left   = theXLeft;
1504   aRect.right  = theXLeft + theWidth;
1505   AdjustWindowRectEx (&aRect, aWinStyle, aMenu != NULL ? TRUE : FALSE, aWinStyleEx);
1506
1507   SetPosition  (aRect.left, aRect.top);
1508   SetDimension (aRect.right - aRect.left, aRect.bottom - aRect.top);
1509   // Save the pointer at the instance associated to the window
1510   SetWindowLongPtrW (win, CLIENTWND, (LONG_PTR)this);
1511   HDC hDC = GetDC(win);
1512   SetBkColor(hDC, RGB(0, 0, 0));
1513   myCurrPen  = 3;
1514   myCurrMode = 3;
1515   SelectObject(hDC, colorPenTab[myCurrPen]); // Default pencil
1516   SelectObject(hDC, GetStockObject(BLACK_BRUSH));
1517   SetTextColor(hDC, RGB(0,0,255));
1518   ReleaseDC(win, hDC);
1519
1520   if (Draw_VirtualWindows)
1521   {
1522     // create a virtual window
1523     SetUseBuffer (Standard_True);
1524   }
1525 }
1526
1527 /*--------------------------------------------------------*\
1528 |  SetUseBuffer
1529 \*--------------------------------------------------------*/
1530 void DrawWindow::SetUseBuffer(Standard_Boolean use)
1531 {
1532   myUseBuffer = use;
1533   InitBuffer();
1534 }
1535
1536 /*--------------------------------------------------------*\
1537 |  InitBuffer
1538 \*--------------------------------------------------------*/
1539 void DrawWindow::InitBuffer()
1540 {
1541   if (myUseBuffer) {
1542     RECT rc;
1543     HDC hDC = GetDC(win);
1544     GetClientRect(win, &rc);
1545     if (myMemHbm) {
1546       BITMAP aBmp;
1547       GetObject(myMemHbm, sizeof(BITMAP), &aBmp);
1548       if (rc.right-rc.left == aBmp.bmWidth && rc.bottom-rc.top == aBmp.bmHeight) return;
1549       DeleteObject(myMemHbm);
1550     }
1551     myMemHbm = (HBITMAP)CreateCompatibleBitmap(hDC,
1552                                       rc.right-rc.left,
1553                                       rc.bottom-rc.top);
1554     HDC aMemDC      = GetMemDC(hDC);
1555     FillRect(aMemDC, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
1556     ReleaseMemDC(aMemDC);
1557     ReleaseDC(win, hDC);
1558   }
1559   else {
1560     if (myMemHbm) {
1561       DeleteObject(myMemHbm);
1562       myMemHbm = NULL;
1563     }
1564   }
1565 }
1566
1567 /*--------------------------------------------------------*\
1568 |  GetMemDC
1569 \*--------------------------------------------------------*/
1570 HDC DrawWindow::GetMemDC(HDC theWinDC)
1571 {
1572   if (!myUseBuffer) return NULL;
1573
1574   HDC aWorkDC = CreateCompatibleDC(theWinDC);
1575   myOldHbm = (HBITMAP)SelectObject(aWorkDC, myMemHbm);
1576   SetROP2(aWorkDC, modeTab[myCurrMode]);
1577   SelectObject(aWorkDC, colorPenTab[myCurrPen]);
1578   SetBkColor(aWorkDC, RGB(0, 0, 0));
1579   SelectObject(aWorkDC, GetStockObject(BLACK_BRUSH));
1580   SetTextColor(aWorkDC, RGB(0,0,255));
1581   return aWorkDC;
1582 }
1583
1584
1585 /*--------------------------------------------------------*\
1586 |  ReleaseMemDC
1587 \*--------------------------------------------------------*/
1588 void DrawWindow::ReleaseMemDC(HDC theMemDC)
1589 {
1590   if (!myUseBuffer || !theMemDC) return;
1591
1592   if (myOldHbm) SelectObject(theMemDC, myOldHbm);
1593   DeleteDC(theMemDC);
1594 }
1595
1596
1597 /*--------------------------------------------------------*\
1598 |  SetPosition
1599 \*--------------------------------------------------------*/
1600 void DrawWindow::SetPosition(Standard_Integer posX, Standard_Integer posY)
1601 {
1602   SetWindowPos(win, 0,
1603                posX, posY,
1604                0, 0,
1605                SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1606 }
1607
1608
1609 /*--------------------------------------------------------*\
1610 |  SetDimension
1611 \*--------------------------------------------------------*/
1612 void DrawWindow::SetDimension(Standard_Integer dimX, Standard_Integer dimY)
1613 {
1614   SetWindowPos(win, 0,
1615                0, 0,
1616                dimX, dimY,
1617                SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
1618 }
1619
1620
1621 /*--------------------------------------------------------*\
1622 |  GetPosition
1623 \*--------------------------------------------------------*/
1624 void DrawWindow::GetPosition(Standard_Integer &dimX,
1625                              Standard_Integer &dimY)
1626 {
1627   RECT rect;
1628   GetWindowRect(win, &rect);
1629
1630   POINT point;
1631   point.x = rect.left;
1632   point.y = rect.top;
1633
1634   ScreenToClient(hWndClientMDI, &point);
1635   dimX = point.x;
1636   dimY = point.y;
1637 }
1638
1639
1640 /*--------------------------------------------------------*\
1641 |  HeightWin
1642 \*--------------------------------------------------------*/
1643 Standard_Integer DrawWindow::HeightWin() const
1644 {
1645   RECT rect;
1646   GetClientRect(win, &rect);
1647   return(rect.bottom-rect.top);
1648 }
1649
1650
1651 /*--------------------------------------------------------*\
1652 |  WidthWin
1653 \*--------------------------------------------------------*/
1654 Standard_Integer DrawWindow::WidthWin() const
1655 {
1656   RECT rect;
1657   GetClientRect(win, &rect);
1658   return(rect.right-rect.left);
1659 }
1660
1661
1662 /*--------------------------------------------------------*\
1663 |  SetTitle
1664 \*--------------------------------------------------------*/
1665 void DrawWindow::SetTitle (const TCollection_AsciiString& theTitle)
1666 {
1667   const TCollection_ExtendedString aTitleW (theTitle);
1668   SetWindowTextW (win, aTitleW.ToWideString());
1669 }
1670
1671
1672 /*--------------------------------------------------------*\
1673 |  GetTitle
1674 \*--------------------------------------------------------*/
1675 TCollection_AsciiString DrawWindow::GetTitle() const
1676 {
1677   wchar_t aTitleW[32];
1678   GetWindowTextW (win, aTitleW, 30);
1679   return TCollection_AsciiString (aTitleW);
1680 }
1681
1682
1683 /*--------------------------------------------------------*\
1684 |  DisplayWindow
1685 \*--------------------------------------------------------*/
1686 void DrawWindow::DisplayWindow()
1687 {
1688   if (Draw_VirtualWindows)
1689   {
1690     return;
1691   }
1692   ShowWindow (win, SW_SHOW);
1693   UpdateWindow (win);
1694 }
1695
1696
1697 /*--------------------------------------------------------*\
1698 |  Hide
1699 \*--------------------------------------------------------*/
1700 void DrawWindow::Hide()
1701 {
1702   ShowWindow(win, SW_HIDE);
1703 }
1704
1705
1706 /*--------------------------------------------------------*\
1707 |  Destroy
1708 \*--------------------------------------------------------*/
1709 void DrawWindow::Destroy()
1710 {
1711   DestroyWindow(win);
1712 }
1713
1714
1715
1716 /*--------------------------------------------------------*\
1717 |  Clear
1718 \*--------------------------------------------------------*/
1719 void DrawWindow::Clear()
1720 {
1721   HDC hDC = GetDC(win);
1722   HDC aWorkDC = myUseBuffer ? GetMemDC(hDC) : hDC;
1723
1724   SaveDC(aWorkDC);
1725   SelectObject(aWorkDC,GetStockObject(BLACK_PEN));
1726   Rectangle(aWorkDC, 0, 0, WidthWin(), HeightWin());
1727   RestoreDC(aWorkDC,-1);
1728
1729   if (myUseBuffer) ReleaseMemDC(aWorkDC);
1730   ReleaseDC(win,hDC);
1731 }
1732
1733 /*--------------------------------------------------------*\
1734 |  SaveBitmap
1735 \*--------------------------------------------------------*/
1736 static Standard_Boolean SaveBitmap (HBITMAP     theHBitmap,
1737                                     const char* theFileName)
1738 {
1739   // Get informations about the bitmap
1740   BITMAP aBitmap;
1741   if (GetObject (theHBitmap, sizeof(BITMAP), (LPSTR )&aBitmap) == 0)
1742   {
1743     return Standard_False;
1744   }
1745
1746   Image_AlienPixMap anImage;
1747   const Standard_Size aSizeRowBytes = Standard_Size(aBitmap.bmWidth) * 4;
1748   if (!anImage.InitTrash (Image_PixMap::ImgBGR32, Standard_Size(aBitmap.bmWidth), Standard_Size(aBitmap.bmHeight), aSizeRowBytes))
1749   {
1750     return Standard_False;
1751   }
1752   anImage.SetTopDown (false);
1753
1754   // Setup image data
1755   BITMAPINFOHEADER aBitmapInfo;
1756   memset (&aBitmapInfo, 0, sizeof(BITMAPINFOHEADER));
1757   aBitmapInfo.biSize        = sizeof(BITMAPINFOHEADER);
1758   aBitmapInfo.biWidth       = aBitmap.bmWidth;
1759   aBitmapInfo.biHeight      = aBitmap.bmHeight; // positive means bottom-up!
1760   aBitmapInfo.biPlanes      = 1;
1761   aBitmapInfo.biBitCount    = 32; // use 32bit for automatic word-alignment per row
1762   aBitmapInfo.biCompression = BI_RGB;
1763
1764   // Copy the pixels
1765   HDC aDC = GetDC (NULL);
1766   Standard_Boolean isSuccess = GetDIBits (aDC, theHBitmap,
1767                                           0,                           // first scan line to set
1768                                           aBitmap.bmHeight,            // number of scan lines to copy
1769                                           anImage.ChangeData(),        // array for bitmap bits
1770                                           (LPBITMAPINFO )&aBitmapInfo, // bitmap data info
1771                                           DIB_RGB_COLORS) != 0;
1772   ReleaseDC (NULL, aDC);
1773   return isSuccess && anImage.Save (theFileName);
1774 }
1775
1776 /*--------------------------------------------------------*\
1777 |  Save
1778 \*--------------------------------------------------------*/
1779 Standard_Boolean DrawWindow::Save (const char* theFileName) const
1780 {
1781   if (myUseBuffer)
1782   {
1783     return SaveBitmap (myMemHbm, theFileName);
1784   }
1785
1786   RECT aRect;
1787   GetClientRect (win, &aRect);
1788   int aWidth  = aRect.right  - aRect.left;
1789   int aHeight = aRect.bottom - aRect.top;
1790
1791   // Prepare the DCs
1792   HDC aDstDC = GetDC (NULL);
1793   HDC aSrcDC = GetDC (win); // we copy only client area
1794   HDC aMemDC = CreateCompatibleDC (aDstDC);
1795
1796   // Copy the screen to the bitmap
1797   HBITMAP anHBitmapDump = CreateCompatibleBitmap (aDstDC, aWidth, aHeight);
1798   HBITMAP anHBitmapOld = (HBITMAP )SelectObject (aMemDC, anHBitmapDump);
1799   BitBlt (aMemDC, 0, 0, aWidth, aHeight, aSrcDC, 0, 0, SRCCOPY);
1800
1801   Standard_Boolean isSuccess = SaveBitmap (anHBitmapDump, theFileName);
1802
1803   // Free objects
1804   DeleteObject (SelectObject (aMemDC, anHBitmapOld));
1805   DeleteDC (aMemDC);
1806
1807   return isSuccess;
1808 }
1809
1810 /*--------------------------------------------------------*\
1811 |  DrawString
1812 \*--------------------------------------------------------*/
1813 void DrawWindow::DrawString(int x,int y, char* text)
1814 {
1815   HDC hDC = GetDC(win);
1816   HDC aWorkDC = myUseBuffer ? GetMemDC(hDC) : hDC;
1817
1818   TCollection_ExtendedString textW (text);
1819   TextOutW(aWorkDC, x, y, (const wchar_t*)textW.ToExtString(), (int )strlen(text));
1820
1821   if (myUseBuffer) ReleaseMemDC(aWorkDC);
1822   ReleaseDC(win,hDC);
1823 }
1824
1825 /*--------------------------------------------------------*\
1826 |  DrawSegments
1827 \*--------------------------------------------------------*/
1828 void DrawWindow::DrawSegments(Segment *tab, int nbElem)
1829 {
1830   HDC hDC = GetDC(win);
1831   HDC aWorkDC = myUseBuffer ? GetMemDC(hDC) : hDC;
1832
1833   for(int i = 0 ; i < nbElem ; i++)
1834   {
1835     MoveToEx(aWorkDC, tab[i].x1, tab[i].y1, NULL);
1836     LineTo(aWorkDC, tab[i].x2, tab[i].y2);
1837   }
1838
1839   if (myUseBuffer) ReleaseMemDC(aWorkDC);
1840   ReleaseDC(win,hDC);
1841 }
1842
1843 /*--------------------------------------------------------*\
1844 |  Redraw
1845 \*--------------------------------------------------------*/
1846 void DrawWindow::Redraw()
1847 {
1848   if (myUseBuffer) {
1849     HDC hDC = GetDC(win);
1850     RECT rc;
1851     GetClientRect(win, &rc);
1852     HDC aMemDC = GetMemDC(hDC);
1853     BitBlt(hDC,
1854            rc.left, rc.top,
1855            rc.right-rc.left, rc.bottom-rc.top,
1856            aMemDC,
1857            0, 0, SRCCOPY);
1858     ReleaseMemDC(aMemDC);
1859     ReleaseDC(win,hDC);
1860   }
1861 }
1862
1863 /*--------------------------------------------------------*\
1864 |  SetMode
1865 \*--------------------------------------------------------*/
1866 void DrawWindow::SetMode(int mode)
1867 {
1868   HDC hDC = GetDC(win);
1869   myCurrMode = mode;
1870   SetROP2(hDC, modeTab[mode]);
1871   ReleaseDC(win,hDC);
1872 }
1873
1874
1875 /*--------------------------------------------------------*\
1876 |  SetColor
1877 \*--------------------------------------------------------*/
1878 void DrawWindow::SetColor(Standard_Integer color)
1879 {
1880   HDC hDC = GetDC(win);
1881   myCurrPen = color;
1882   SelectObject(hDC,colorPenTab[color]);
1883   ReleaseDC(win,hDC);
1884 }
1885
1886
1887 /*--------------------------------------------------------*\
1888 |  WExpose
1889 \*--------------------------------------------------------*/
1890 void DrawWindow::WExpose()
1891 {
1892 }
1893
1894
1895 /*--------------------------------------------------------*\
1896 |  WButtonPress
1897 \*--------------------------------------------------------*/
1898 void DrawWindow::WButtonPress(const Standard_Integer,
1899                                const Standard_Integer,
1900                                const Standard_Integer&)
1901 {
1902 }
1903
1904
1905 /*--------------------------------------------------------*\
1906 |  WButtonRelease
1907 \*--------------------------------------------------------*/
1908 void DrawWindow::WButtonRelease(const Standard_Integer,
1909                                  const Standard_Integer,
1910                                  const Standard_Integer&)
1911 {
1912 }
1913
1914
1915 /*--------------------------------------------------------*\
1916 |  WMotionNotify
1917 \*--------------------------------------------------------*/
1918 void Draw_Window::WMotionNotify(const Standard_Integer ,
1919                                 const Standard_Integer )
1920 {
1921 }
1922
1923
1924 /*--------------------------------------------------------*\
1925 |  WConfigureNotify
1926 \*--------------------------------------------------------*/
1927 void DrawWindow::WConfigureNotify(const Standard_Integer,
1928                                    const Standard_Integer,
1929                                    const Standard_Integer,
1930                                    const Standard_Integer)
1931 {
1932 }
1933
1934
1935 /*--------------------------------------------------------*\
1936 |  WUnmapNotify
1937 \*--------------------------------------------------------*/
1938 void DrawWindow::WUnmapNotify()
1939 {
1940 }
1941
1942
1943
1944 /*
1945 **  IMPLEMENTATION of the CLASS SEGMENT
1946  */
1947
1948 /*--------------------------------------------------------*\
1949 |  Init
1950 \*--------------------------------------------------------*/
1951
1952 void Segment::Init(Standard_Integer a1, Standard_Integer a2,
1953                    Standard_Integer a3, Standard_Integer a4)
1954 {
1955   x1=a1;
1956   y1=a2;
1957   x2=a3;
1958   y2=a4;
1959 }
1960
1961 static DWORD WINAPI tkLoop(VOID);
1962 #ifdef _TK
1963 static Tk_Window mainWindow;
1964 #endif
1965
1966 //* threads sinchronization *//
1967 DWORD  dwMainThreadId;
1968 console_semaphore_value volatile console_semaphore = WAIT_CONSOLE_COMMAND;
1969 #define THE_COMMAND_SIZE 1000     /* Console Command size */
1970 wchar_t console_command[THE_COMMAND_SIZE];
1971 bool volatile isTkLoopStarted = false;
1972
1973 /*--------------------------------------------------------*\
1974 |  Init_Appli
1975 \*--------------------------------------------------------*/
1976 Standard_Boolean Init_Appli(HINSTANCE hInst,
1977                             HINSTANCE hPrevInst, int nShow, HWND& hWndFrame )
1978 {
1979   Draw_Interpretor& aCommands = Draw::GetInterpretor();
1980
1981   DWORD IDThread;
1982   HANDLE hThread;
1983   console_semaphore = STOP_CONSOLE;
1984   aCommands.Init();
1985   interp = aCommands.Interp();
1986   Tcl_Init(interp) ;
1987
1988   dwMainThreadId = GetCurrentThreadId();
1989
1990   //necessary for normal Tk operation
1991   hThread = CreateThread(NULL, // no security attributes
1992                            0,                           // use default stack size
1993                            (LPTHREAD_START_ROUTINE) tkLoop, // thread function
1994                            NULL,                    // no thread function argument
1995                            0,                       // use default creation flags
1996                            &IDThread);
1997   if (!hThread) {
1998     cout << "Tcl/Tk main loop thread not created. Switching to batch mode..." << endl;
1999 #ifdef _TK
2000     try {
2001       OCC_CATCH_SIGNALS
2002       Tk_Init(interp) ;
2003     } catch  (Standard_Failure) {
2004       cout <<" Pb au lancement de TK_Init "<<endl;
2005     }
2006
2007     Tcl_StaticPackage(interp, "Tk", Tk_Init, (Tcl_PackageInitProc *) NULL);
2008 #endif
2009     //since the main Tcl/Tk loop wasn't created --> switch to batch mode
2010     return Standard_False;
2011   }
2012
2013   // san - 06/08/2002 - Time for tkLoop to start; Tk fails to initialize otherwise
2014   while (!isTkLoopStarted)
2015     Sleep(10);
2016
2017   // Saving of window classes
2018   if(!hPrevInst)
2019     if(!RegisterAppClass(hInst))
2020       return(Standard_False);
2021
2022   /*
2023    ** Enter the application message-polling loop.  This is the anchor for
2024    ** the application.
2025   */
2026   hWndFrame = !Draw_IsConsoleSubsystem ? CreateAppWindow (hInst) : NULL;
2027   if (hWndFrame != NULL)
2028   {
2029     ShowWindow(hWndFrame,nShow);
2030     UpdateWindow(hWndFrame);
2031   }
2032
2033   return Standard_True;
2034 }
2035
2036 Standard_Boolean Draw_Interprete (const char*);
2037
2038 /*--------------------------------------------------------*\
2039 |  readStdinThreadFunc
2040 \*--------------------------------------------------------*/
2041 static DWORD WINAPI readStdinThreadFunc()
2042 {
2043   if (!Draw_IsConsoleSubsystem)
2044   {
2045     return 1;
2046   }
2047
2048   // Console locale could be set to the system codepage .OCP (UTF-8 is not properly supported on Windows).
2049   // However, to use it, we have to care using std::wcerr/fwprintf/WriteConsoleW for non-ascii strings everywhere (including Tcl itself),
2050   // or otherwise we can have incomplete output issues
2051   // (e.g. UNICODE string will be NOT just corrupted as in case when we don't set setlocale()
2052   // but will break further normal output to console due to special characters being accidentally handled by console in the wrong way).
2053   //setlocale (LC_ALL, ".OCP");
2054
2055   // _O_U16TEXT can be used with fgetws() to get similar result as ReadConsoleW() without affecting setlocale(),
2056   // however it would break pipe input
2057   //_setmode (_fileno(stdin), _O_U16TEXT);
2058
2059   bool isConsoleInput = true;
2060   for (;;)
2061   {
2062     while (console_semaphore != WAIT_CONSOLE_COMMAND)
2063     {
2064       Sleep (100);
2065     }
2066
2067     const HANDLE anStdIn = ::GetStdHandle (STD_INPUT_HANDLE);
2068     if (anStdIn != NULL
2069      && anStdIn != INVALID_HANDLE_VALUE
2070      && isConsoleInput)
2071     {
2072       DWORD aNbRead = 0;
2073       if (ReadConsoleW (anStdIn, console_command, THE_COMMAND_SIZE, &aNbRead, NULL))
2074       {
2075         console_command[aNbRead] = L'\0';
2076         console_semaphore = HAS_CONSOLE_COMMAND;
2077         continue;
2078       }
2079       else
2080       {
2081         const DWORD anErr = GetLastError();
2082         if (anErr != ERROR_SUCCESS)
2083         {
2084           // fallback using fgetws() which would work with pipes
2085           // but supports Unicode only through multi-byte encoding (which is not UTF-8)
2086           isConsoleInput = false;
2087           continue;
2088         }
2089       }
2090     }
2091
2092     // fgetws() works only for characters within active locale (see setlocale())
2093     if (fgetws (console_command, THE_COMMAND_SIZE, stdin))
2094     {
2095       console_semaphore = HAS_CONSOLE_COMMAND;
2096     }
2097   }
2098 }
2099
2100 /*--------------------------------------------------------*\
2101 |  exitProc: finalization handler for Tcl/Tk thread. Forces parent process to die
2102 \*--------------------------------------------------------*/
2103 void exitProc(ClientData /*dc*/)
2104 {
2105   NCollection_List<Draw_Window::FCallbackBeforeTerminate>::Iterator Iter(MyCallbacks);
2106   for(; Iter.More(); Iter.Next())
2107   {
2108       (*Iter.Value())();
2109   }
2110   HANDLE proc = GetCurrentProcess();
2111   TerminateProcess(proc, 0);
2112 }
2113
2114 /*--------------------------------------------------------*\
2115 |  tkLoop: implements Tk_Main()-like behaviour in a separate thread
2116 \*--------------------------------------------------------*/
2117 static DWORD WINAPI tkLoop(VOID)
2118 {
2119   Draw_Interpretor& aCommands = Draw::GetInterpretor();
2120
2121   Tcl_CreateExitHandler(exitProc, 0);
2122 #if (TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5))
2123   {
2124     Tcl_Channel aChannelIn  = Tcl_GetStdChannel (TCL_STDIN);
2125     Tcl_Channel aChannelOut = Tcl_GetStdChannel (TCL_STDOUT);
2126     Tcl_Channel aChannelErr = Tcl_GetStdChannel (TCL_STDERR);
2127     if (aChannelIn != NULL)
2128     {
2129       Tcl_RegisterChannel (aCommands.Interp(), aChannelIn);
2130     }
2131     if (aChannelOut != NULL)
2132     {
2133       Tcl_RegisterChannel (aCommands.Interp(), aChannelOut);
2134     }
2135     if (aChannelErr != NULL)
2136     {
2137       Tcl_RegisterChannel (aCommands.Interp(), aChannelErr);
2138     }
2139   }
2140 #endif
2141
2142 #ifdef _TK
2143   // initialize the Tk library if not in 'virtual windows' mode
2144   // (virtual windows are created by OCCT with native APIs,
2145   // thus Tk will be useless)
2146   if (!Draw_VirtualWindows)
2147   {
2148     try
2149     {
2150       OCC_CATCH_SIGNALS
2151       Standard_Integer res = Tk_Init (interp);
2152       if (res != TCL_OK)
2153       {
2154 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
2155         cout << "tkLoop: error in Tk initialization. Tcl reported: " << Tcl_GetStringResult(interp) << endl;
2156 #else
2157         cout << "tkLoop: error in Tk initialization. Tcl reported: " << interp->result << endl;
2158 #endif
2159       }
2160     }
2161     catch (Standard_Failure)
2162     {
2163       cout << "tkLoop: exception in TK_Init\n";
2164     }
2165     Tcl_StaticPackage (interp, "Tk", Tk_Init, (Tcl_PackageInitProc* ) NULL);
2166     mainWindow = Tk_MainWindow (interp);
2167     if (mainWindow == NULL)
2168     {
2169 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
2170       fprintf (stderr, "%s\n", Tcl_GetStringResult(interp));
2171 #else
2172       fprintf (stderr, "%s\n", interp->result);
2173 #endif
2174       cout << "tkLoop: Tk_MainWindow() returned NULL. Exiting...\n";
2175       Tcl_Exit (0);
2176     }
2177     Tk_Name(mainWindow) = Tk_GetUid (Tk_SetAppName (mainWindow, "Draw"));
2178   }
2179 #endif //#ifdef _TK
2180
2181   // set signal handler in the new thread
2182   OSD::SetSignal(Standard_False);
2183
2184   // inform the others that we have started
2185   isTkLoopStarted = true;
2186
2187   while (console_semaphore == STOP_CONSOLE)
2188     Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT);
2189
2190   if (Draw_IsConsoleSubsystem && console_semaphore == WAIT_CONSOLE_COMMAND)
2191     Prompt(interp, 0);
2192
2193   //process a command
2194   Standard_Boolean toLoop = Standard_True;
2195   while (toLoop)
2196   {
2197     while(Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT));
2198     if (console_semaphore == HAS_CONSOLE_COMMAND)
2199     {
2200       TCollection_AsciiString aCmdUtf8 (console_command);
2201       if (Draw_Interprete (aCmdUtf8.ToCString()))
2202       {
2203         if (Draw_IsConsoleSubsystem) Prompt (interp, 0);
2204       }
2205       else
2206       {
2207         if (Draw_IsConsoleSubsystem) Prompt (interp, 1);
2208       }
2209       console_semaphore = WAIT_CONSOLE_COMMAND;
2210     }
2211     else
2212     {
2213       Sleep(100);
2214     }
2215   #ifdef _TK
2216     // We should not exit until the Main Tk window is closed
2217     toLoop = (Tk_GetNumMainWindows() > 0) || Draw_VirtualWindows;
2218   #endif
2219   }
2220   Tcl_Exit(0);
2221   return 0;
2222 }
2223
2224
2225 /*--------------------------------------------------------*\
2226 |  Run_Appli
2227 \*--------------------------------------------------------*/
2228 void Run_Appli(HWND hWnd)
2229 {
2230   MSG msg;
2231   HACCEL hAccel = NULL;
2232
2233   msg.wParam = 1;
2234
2235 //  if (!(hAccel = LoadAccelerators (hInstance, MAKEINTRESOURCE(ACCEL_ID))))
2236 //        MessageBox(hWnd, "MDI: Load Accel failure!", "Error", MB_OK);
2237   DWORD IDThread;
2238   HANDLE hThread;
2239   if (Draw_IsConsoleSubsystem) {
2240     hThread = CreateThread(NULL, // no security attributes
2241                            0,                           // use default stack size
2242                            (LPTHREAD_START_ROUTINE) readStdinThreadFunc, // thread function
2243                            NULL,                    // no thread function argument
2244                            0,                       // use default creation flags
2245                            &IDThread);              // returns thread identifier
2246     if (!hThread) {
2247       cout << "pb in creation of the thread reading stdin" << endl;
2248       Draw_IsConsoleSubsystem = Standard_False;
2249       Init_Appli (GetModuleHandleW (NULL),
2250                   GetModuleHandleW (NULL),
2251                   1, hWnd); // reinit => create MDI client wnd
2252     }
2253   }
2254
2255   //turn on the command interpretation mechanism (regardless of the mode)
2256   if (console_semaphore == STOP_CONSOLE)
2257     console_semaphore = WAIT_CONSOLE_COMMAND;
2258
2259   //simple Win32 message loop
2260   while (GetMessageW (&msg, NULL, 0, 0) > 0)
2261   {
2262     if (!TranslateAcceleratorW (hWnd, hAccel, &msg))
2263     {
2264       TranslateMessage (&msg);
2265       DispatchMessageW (&msg);
2266     }
2267   }
2268   ExitProcess(0);
2269 }
2270
2271
2272 /*--------------------------------------------------------*\
2273 |  Destroy_Appli
2274 \*--------------------------------------------------------*/
2275 void Destroy_Appli(HINSTANCE hInst)
2276 {
2277   UnregisterAppClass(hInst);
2278   for (int i = 0 ; i < MAXCOLOR ; i++)
2279     DeleteObject(colorPenTab[i]);
2280 }
2281
2282 /*--------------------------------------------------------*\
2283 |  SelectWait
2284 \*--------------------------------------------------------*/
2285 void DrawWindow::SelectWait(HANDLE& hWnd, int& x, int& y, int& button)
2286 {
2287   MSG msg;
2288
2289   msg.wParam = 1;
2290
2291   GetMessageW (&msg, NULL, 0, 0);
2292   while((msg.message != WM_RBUTTONDOWN && msg.message != WM_LBUTTONDOWN) ||
2293         ! ( Draw_IsConsoleSubsystem || IsChild(DrawWindow::hWndClientMDI,msg.hwnd)) )
2294   {
2295     GetMessageW (&msg, NULL, 0, 0);
2296   }
2297
2298   hWnd = msg.hwnd;
2299   x = LOWORD(msg.lParam);
2300   y = HIWORD(msg.lParam);
2301   if (msg.message == WM_LBUTTONDOWN)
2302     button = 1;
2303   else
2304     button = 3;
2305 }
2306
2307 /*--------------------------------------------------------*\
2308 |  SelectNoWait
2309 \*--------------------------------------------------------*/
2310 void DrawWindow::SelectNoWait(HANDLE& hWnd, int& x, int& y, int& button)
2311 {
2312   MSG msg;
2313
2314   msg.wParam = 1;
2315
2316   GetMessageW (&msg,NULL,0,0);
2317   while((msg.message != WM_RBUTTONDOWN && msg.message != WM_LBUTTONDOWN &&
2318         msg.message != WM_MOUSEMOVE) ||
2319         ! ( Draw_IsConsoleSubsystem || IsChild(DrawWindow::hWndClientMDI,msg.hwnd) ) )
2320   {
2321     GetMessageW(&msg,NULL,0,0);
2322   }
2323   hWnd = msg.hwnd;
2324   x = LOWORD(msg.lParam);
2325   y = HIWORD(msg.lParam);
2326   switch (msg.message)
2327   {
2328     case WM_LBUTTONDOWN :
2329                     button = 1;
2330                     break;
2331
2332     case WM_RBUTTONDOWN :
2333                     button = 3;
2334                     break;
2335
2336     case WM_MOUSEMOVE :
2337                     button = 0;
2338                     break;
2339   }
2340 }
2341
2342 Standard_Boolean DrawWindow::DefineColor (const Standard_Integer, const char*)
2343 {
2344   return Standard_True;
2345 };
2346
2347 #endif