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