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