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