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