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