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
6 // This file is part of Open CASCADE Technology software library.
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.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 // include windows.h first to have all definitions available
22 #include <Standard_ErrorHandler.hxx>
25 #include <Draw_Interpretor.hxx>
26 #include <Draw_Window.hxx>
27 #include <Draw_Appli.hxx>
28 #include <TCollection_AsciiString.hxx>
29 #include <TCollection_ExtendedString.hxx>
30 #include <Image_AlienPixMap.hxx>
31 #include <NCollection_List.hxx>
33 extern Standard_Boolean Draw_Batch;
34 extern Standard_Boolean Draw_VirtualWindows;
35 static NCollection_List<Draw_Window::FCallbackBeforeTerminate> MyCallbacks;
37 void Draw_Window::AddCallbackBeforeTerminate(FCallbackBeforeTerminate theCB)
39 MyCallbacks.Append(theCB);
42 void Draw_Window::RemoveCallbackBeforeTerminate(FCallbackBeforeTerminate theCB)
44 NCollection_List<Draw_Window::FCallbackBeforeTerminate>::Iterator Iter(MyCallbacks);
45 for(; Iter.More(); Iter.Next())
47 if (Iter.Value() == theCB)
49 MyCallbacks.Remove(Iter);
56 *----------------------------------------------------------------------
60 * Issue a prompt on standard output, or invoke a script
61 * to issue the prompt.
67 * A prompt gets output, and a Tcl script may be evaluated
70 *----------------------------------------------------------------------
73 static void Prompt(Tcl_Interp *Interp, int partial)
75 Tcl_Channel errChannel;
76 Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT);
77 const char* promptCmd = Tcl_GetVar (Interp, partial ? "tcl_prompt2" : "tcl_prompt1", TCL_GLOBAL_ONLY);
78 if (promptCmd == NULL) {
80 if (!partial && outChannel) {
81 Tcl_Write(outChannel, "% ", 2);
84 int code = Tcl_Eval(Interp, promptCmd);
85 outChannel = Tcl_GetStdChannel(TCL_STDOUT);
86 errChannel = Tcl_GetStdChannel(TCL_STDERR);
89 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
90 Tcl_Write(errChannel, Tcl_GetStringResult(Interp), -1);
92 Tcl_Write(errChannel, Interp->result, -1);
94 Tcl_Write(errChannel, "\n", 1);
96 Tcl_AddErrorInfo(Interp,
97 "\n (script that generates prompt)");
102 Tcl_Flush(outChannel);
106 #if !defined(_WIN32) && !defined(__WIN32__)
108 #include <OSD_Timer.hxx>
109 #include <Draw_Window.hxx>
112 #if defined(__APPLE__) && !defined(MACOSX_USE_GLX)
113 // use forward declaration for small subset of used Tk functions
114 // to workaround broken standard Tk framework installation within OS X SDKs
115 // which *HAS* X11 headers in Tk.framework but doesn't install them appropriately
117 typedef struct Tk_Window_* Tk_Window;
118 typedef const char* Tk_Uid;
120 extern "C" int Tk_Init (Tcl_Interp* interp);
121 extern "C" void Tk_MainLoop();
122 extern "C" Tk_Window Tk_MainWindow (Tcl_Interp* interp) ;
123 extern "C" Tk_Uid Tk_GetUid (const char* str);
124 extern "C" const char* Tk_SetAppName (Tk_Window tkwin, const char* name) ;
125 extern "C" void Tk_GeometryRequest (Tk_Window tkwin, int reqWidth, int reqHeight);
132 * Global variables used by the main program:
135 char *tcl_RcFileName = NULL; /* Name of a user-specific startup script
136 * to source if the application is being run
137 * interactively (e.g. "~/.wishrc"). Set
138 * by Tcl_AppInit. NULL means don't source
141 static Tcl_DString command; /* Used to assemble lines of terminal input
142 * into Tcl commands. */
143 static Tcl_DString line; /* Used to read the next line from the
145 //static char errorExitCmd[] = "exit 1";
148 * Forward declarations for procedures defined later in this file:
151 static void StdinProc (ClientData clientData, int mask);
153 static void Prompt (Tcl_Interp *Interp, int partial);
155 static Standard_Boolean tty; /* Non-zero means standard input is a
156 * terminal-like device. Zero means it's
159 Standard_Integer Draw_WindowScreen = 0;
160 Standard_Boolean Draw_BlackBackGround = Standard_True;
163 // Initialization of static variables of Draw_Window
164 //======================================================
165 Draw_Window* Draw_Window::firstWindow = NULL;
168 #if !defined(__APPLE__) || defined(MACOSX_USE_GLX)
169 #include <X11/Xutil.h>
170 #include <Aspect_DisplayConnection.hxx>
172 static unsigned long thePixels[MAXCOLOR];
174 Display* Draw_WindowDisplay = NULL;
175 Colormap Draw_WindowColorMap;
176 static Handle(Aspect_DisplayConnection) Draw_DisplayConnection;
178 // Base_Window struct definition
179 //===================================
183 XSetWindowAttributes xswa;
186 //=======================================================================
187 //function : Draw_Window
189 //=======================================================================
190 Draw_Window::Draw_Window() :
191 base(*new Base_Window()),
196 myUseBuffer(Standard_False),
197 withWindowManager(Standard_True)
199 myMother = RootWindow(Draw_WindowDisplay,
202 if (firstWindow) firstWindow->previous = this;
206 //=======================================================================
207 //function : Draw_Window
209 //=======================================================================
210 Draw_Window::Draw_Window(Window mother) :
211 base(*new Base_Window()),
216 myUseBuffer(Standard_False),
217 withWindowManager(Standard_True)
221 if (firstWindow) firstWindow->previous = this;
225 //=======================================================================
226 //function : Draw_Window
228 //=======================================================================
229 Draw_Window::Draw_Window (const char* title,
230 Standard_Integer X, Standard_Integer Y,
231 Standard_Integer DX, Standard_Integer DY) :
232 base(*new Base_Window()),
237 myUseBuffer(Standard_False),
238 withWindowManager(Standard_True)
240 myMother = RootWindow(Draw_WindowDisplay,
243 if (firstWindow) firstWindow->previous = this;
249 //=======================================================================
250 //function : Draw_Window
252 //=======================================================================
253 Draw_Window::Draw_Window (const char* window ) :
254 base(*new Base_Window()),
259 myUseBuffer(Standard_False),
260 withWindowManager(Standard_True)
262 sscanf(window,"%lx",&win);
263 Standard_Integer X,Y,DX,DY;
265 if (firstWindow) firstWindow->previous = this;
274 //=======================================================================
275 //function : Draw_Window
277 //=======================================================================
278 Draw_Window::Draw_Window (Window mother,
280 Standard_Integer X, Standard_Integer Y,
281 Standard_Integer DX, Standard_Integer DY) :
282 base(*new Base_Window()),
287 myUseBuffer(Standard_False),
288 withWindowManager(Standard_True)
292 if (firstWindow) firstWindow->previous = this;
298 //=======================================================================
299 //function : ~Draw_Window
301 //=======================================================================
302 Draw_Window::~Draw_Window()
305 previous->next = next;
309 next->previous = previous;
313 XFreePixmap(Draw_WindowDisplay, myBuffer);
316 // Liberation pointer on Base_Window
320 //=======================================================================
323 //=======================================================================
324 void Draw_Window::Init(Standard_Integer X, Standard_Integer Y,
325 Standard_Integer DX, Standard_Integer DY)
327 unsigned long setmask;
329 if (Draw_BlackBackGround)
331 base.xswa.background_pixel = BlackPixel(Draw_WindowDisplay,Draw_WindowScreen);
332 base.xswa.border_pixel = WhitePixel(Draw_WindowDisplay,Draw_WindowScreen);
336 base.xswa.background_pixel = WhitePixel(Draw_WindowDisplay,Draw_WindowScreen);
337 base.xswa.border_pixel = BlackPixel(Draw_WindowDisplay,Draw_WindowScreen);
339 base.xswa.colormap = Draw_WindowColorMap;
340 setmask = CWBackPixel | CWBorderPixel ;
343 myHints.flags = USPosition;
349 win = XCreateWindow(Draw_WindowDisplay,
352 (unsigned int) DX,(unsigned int) DY,
354 DefaultDepth(Draw_WindowDisplay,Draw_WindowScreen),
356 DefaultVisual(Draw_WindowDisplay,Draw_WindowScreen),
358 XSelectInput(Draw_WindowDisplay, win, ButtonPressMask|ExposureMask|
359 StructureNotifyMask);
361 // advise to the window manager to place it where I need
362 XSetWMNormalHints(Draw_WindowDisplay,win,&myHints);
364 Atom aDeleteWindowAtom = Draw_DisplayConnection->GetAtom (Aspect_XA_DELETE_WINDOW);
365 XSetWMProtocols (Draw_WindowDisplay, win, &aDeleteWindowAtom, 1);
367 if (Draw_VirtualWindows)
369 myUseBuffer = Standard_True;
374 base.gc = XCreateGC(Draw_WindowDisplay, win, 0, NULL);
376 XSetPlaneMask(Draw_WindowDisplay,base.gc,AllPlanes);
377 XSetForeground(Draw_WindowDisplay,
378 base.gc, WhitePixel(Draw_WindowDisplay,Draw_WindowScreen));
379 XSetBackground(Draw_WindowDisplay,
380 base.gc, BlackPixel(Draw_WindowDisplay,Draw_WindowScreen));
381 // save in case of window recovery
383 base.xswa.backing_store = Always;
384 XChangeWindowAttributes(Draw_WindowDisplay, win,
385 CWBackingStore, &base.xswa);
387 XSetLineAttributes (Draw_WindowDisplay, base.gc,
388 0, LineSolid, CapButt, JoinMiter);
391 //=======================================================================
392 //function : InitBuffer
394 //=======================================================================
395 void Draw_Window::InitBuffer()
399 XFreePixmap (Draw_WindowDisplay, myBuffer);
401 XWindowAttributes winAttr;
402 XGetWindowAttributes (Draw_WindowDisplay, win, &winAttr);
403 myBuffer = XCreatePixmap (Draw_WindowDisplay, win, winAttr.width, winAttr.height, winAttr.depth);
405 else if (myBuffer != 0)
407 XFreePixmap (Draw_WindowDisplay, myBuffer);
412 //=======================================================================
413 //function : StopWinManager
415 //=======================================================================
416 void Draw_Window::StopWinManager()
419 XWindowAttributes winAttr;
420 XGetWindowAttributes (Draw_WindowDisplay, win, &winAttr);
424 myHints.flags = USPosition;
425 myHints.x = (int) 30;
426 myHints.y = (int) 100;
428 base.xswa.override_redirect = 1;
429 base.xswa.border_pixel = BlackPixel(Draw_WindowDisplay,
431 base.xswa.background_pixel = WhitePixel(Draw_WindowDisplay,
434 withWindowManager = Standard_False;
436 win = XCreateWindow(Draw_WindowDisplay, myMother,
437 winAttr.x, winAttr.y,
438 winAttr.width, winAttr.height,
440 CopyFromParent, InputOutput, CopyFromParent,
441 CWBorderPixel|CWOverrideRedirect|CWBackPixel, &base.xswa);
444 // adwise to the window manager to place it where I wish
445 XSetWMNormalHints(Draw_WindowDisplay,win,&myHints);
447 // all masks of the old window are reassigned to the new one.
448 XSelectInput(Draw_WindowDisplay,win,winAttr.your_event_mask);
451 //=======================================================================
452 //function : SetPosition
454 //=======================================================================
455 void Draw_Window::SetPosition(Standard_Integer NewXpos,
456 Standard_Integer NewYpos)
458 Standard_Integer x,y;
461 if ( (x != NewXpos) || (y != NewYpos) )
462 XMoveWindow(Draw_WindowDisplay, win, NewXpos, NewYpos);
465 //=======================================================================
466 //function : SetDimension
468 //=======================================================================
469 void Draw_Window::SetDimension(Standard_Integer NewDx,
470 Standard_Integer NewDy)
472 if ( (NewDx != WidthWin() ) || (NewDy != HeightWin() ) )
473 XResizeWindow(Draw_WindowDisplay, win, NewDx, NewDy);
476 //=======================================================================
477 //function : GetPosition
479 //=======================================================================
480 void Draw_Window::GetPosition(Standard_Integer &PosX,
481 Standard_Integer &PosY)
483 XWindowAttributes winAttr;
484 XGetWindowAttributes(Draw_WindowDisplay, win, &winAttr);
490 //=======================================================================
491 //function : HeightWin
493 //=======================================================================
494 Standard_Integer Draw_Window::HeightWin() const
497 XWindowAttributes winAttr;
498 XGetWindowAttributes(Draw_WindowDisplay, win, &winAttr);
504 //=======================================================================
505 //function : WidthWin
507 //=======================================================================
508 Standard_Integer Draw_Window::WidthWin() const
511 XWindowAttributes winAttr;
512 XGetWindowAttributes(Draw_WindowDisplay, win, &winAttr);
518 //=======================================================================
519 //function : SetTitle
521 //=======================================================================
522 void Draw_Window::SetTitle(const TCollection_AsciiString& theTitle)
524 XStoreName (Draw_WindowDisplay, win, theTitle.ToCString());
527 //=======================================================================
528 //function : GetTitle
530 //=======================================================================
531 TCollection_AsciiString Draw_Window::GetTitle() const
534 XFetchName (Draw_WindowDisplay, win, &aTitle);
535 return TCollection_AsciiString (aTitle);
538 //=======================================================================
539 //function : GetDrawable
541 //=======================================================================
542 Drawable Draw_Window::GetDrawable() const
544 return myUseBuffer ? myBuffer : win;
547 //=======================================================================
548 //function :DefineColor
550 //=======================================================================
551 Standard_Boolean Draw_Window::DefineColor(const Standard_Integer i, const char* colorName)
555 if (!XParseColor(Draw_WindowDisplay,Draw_WindowColorMap,colorName,&color))
556 return Standard_False;
557 if (!XAllocColor(Draw_WindowDisplay,Draw_WindowColorMap,&color))
558 return Standard_False;
559 thePixels[i % MAXCOLOR] = color.pixel;
560 return Standard_True;
563 //=======================================================================
564 //function : IsMapped
566 //=======================================================================
567 bool Draw_Window::IsMapped() const
569 if (Draw_VirtualWindows
575 XFlush (Draw_WindowDisplay);
576 XWindowAttributes aWinAttr;
577 XGetWindowAttributes (Draw_WindowDisplay, win, &aWinAttr);
578 return aWinAttr.map_state == IsUnviewable
579 || aWinAttr.map_state == IsViewable;
582 //=======================================================================
583 //function : DisplayWindow
585 //=======================================================================
586 void Draw_Window::DisplayWindow()
588 if (Draw_VirtualWindows)
594 XMapRaised(Draw_WindowDisplay, win);
596 XFlush(Draw_WindowDisplay);
599 //=======================================================================
602 //=======================================================================
603 void Draw_Window::Hide()
605 XUnmapWindow(Draw_WindowDisplay, win);
608 //=======================================================================
611 //=======================================================================
612 void Draw_Window::Destroy()
614 XFreeGC (Draw_WindowDisplay, base.gc);
615 XDestroyWindow(Draw_WindowDisplay, win);
619 XFreePixmap(Draw_WindowDisplay, myBuffer);
624 //=======================================================================
627 //=======================================================================
628 void Draw_Window::Clear()
632 // XClearArea only applicable for windows
633 XGCValues currValues;
634 XGetGCValues(Draw_WindowDisplay, base.gc, GCBackground | GCForeground, &currValues);
635 XSetForeground(Draw_WindowDisplay, base.gc, currValues.background);
636 XFillRectangle(Draw_WindowDisplay, myBuffer, base.gc, 0, 0, WidthWin(), HeightWin());
637 XSetForeground(Draw_WindowDisplay, base.gc, currValues.foreground);
641 XClearArea(Draw_WindowDisplay, win, 0, 0, 0, 0, False);
645 //=======================================================================
648 //=======================================================================
649 void Draw_Window::Flush()
651 XFlush(Draw_WindowDisplay);
654 //=======================================================================
655 //function : DrawString
657 //=======================================================================
658 void Draw_Window::DrawString(int X, int Y, char *text)
660 XDrawString(Draw_WindowDisplay, GetDrawable(), base.gc, X, Y, text, strlen(text));
663 //=======================================================================
664 //function : DrawSegments
666 //=======================================================================
667 void Draw_Window::DrawSegments(Segment *tab, int nbElem)
669 XDrawSegments(Draw_WindowDisplay, GetDrawable(), base.gc, (XSegment*) tab, nbElem);
672 //=======================================================================
675 //=======================================================================
676 void Draw_Window::Redraw()
679 XCopyArea (Draw_WindowDisplay,
680 myBuffer, win, // source, destination Drawables
683 WidthWin(), HeightWin(),
684 0, 0); // destination x, y
688 //=======================================================================
689 //function : SetColor
691 //=======================================================================
692 void Draw_Window::SetColor(Standard_Integer color)
694 XSetForeground(Draw_WindowDisplay, base.gc, thePixels[color]);
697 //=======================================================================
700 //=======================================================================
701 void Draw_Window::SetMode( int mode)
703 XSetFunction(Draw_WindowDisplay, base.gc, mode);
706 //=======================================================================
709 //=======================================================================
710 Standard_Boolean Draw_Window::Save (const char* theFileName) const
712 // make sure all draw operations done
713 XSync (Draw_WindowDisplay, True);
716 XWindowAttributes winAttr;
717 XGetWindowAttributes (Draw_WindowDisplay, win, &winAttr);
721 // make sure that the whole window fit on display to prevent BadMatch error
722 XWindowAttributes winAttrRoot;
723 XGetWindowAttributes (Draw_WindowDisplay, XRootWindowOfScreen (winAttr.screen), &winAttrRoot);
725 Window winChildDummy;
728 XTranslateCoordinates (Draw_WindowDisplay, win, XRootWindowOfScreen (winAttr.screen),
729 0, 0, &winLeft, &winTop, &winChildDummy);
731 if (((winLeft + winAttr.width) > winAttrRoot.width) || winLeft < winAttrRoot.x ||
732 ((winTop + winAttr.height) > winAttrRoot.height) || winTop < winAttrRoot.y)
734 std::cerr << "The window not fully visible! Can't create the snapshot.\n";
735 return Standard_False;
740 if (XMatchVisualInfo (Draw_WindowDisplay, Draw_WindowScreen, 32, TrueColor, &aVInfo) == 0
741 && XMatchVisualInfo (Draw_WindowDisplay, Draw_WindowScreen, 24, TrueColor, &aVInfo) == 0)
743 std::cerr << "24-bit TrueColor visual is not supported by server!\n";
744 return Standard_False;
747 Image_AlienPixMap anImage;
748 bool isBigEndian = Image_PixMap::IsBigEndianHost();
749 const Standard_Size aSizeRowBytes = Standard_Size(winAttr.width) * 4;
750 if (!anImage.InitTrash (isBigEndian ? Image_Format_RGB32 : Image_Format_BGR32,
751 Standard_Size(winAttr.width), Standard_Size(winAttr.height), aSizeRowBytes))
753 return Standard_False;
755 anImage.SetTopDown (true);
757 XImage* anXImage = XCreateImage (Draw_WindowDisplay, aVInfo.visual,
758 32, ZPixmap, 0, (char* )anImage.ChangeData(), winAttr.width, winAttr.height, 32, int(aSizeRowBytes));
759 anXImage->bitmap_bit_order = anXImage->byte_order = (isBigEndian ? MSBFirst : LSBFirst);
760 if (XGetSubImage (Draw_WindowDisplay, GetDrawable(),
761 0, 0, winAttr.width, winAttr.height,
762 AllPlanes, ZPixmap, anXImage, 0, 0) == NULL)
764 anXImage->data = NULL;
765 XDestroyImage (anXImage);
766 return Standard_False;
770 anXImage->data = NULL;
771 XDestroyImage (anXImage);
774 return anImage.Save (theFileName);
777 //=======================================================================
780 //=======================================================================
782 void Draw_Window::Wait (Standard_Boolean wait)
786 XSelectInput(Draw_WindowDisplay,win,
787 ButtonPressMask|ExposureMask | StructureNotifyMask |
791 XSelectInput(Draw_WindowDisplay,win,
792 ButtonPressMask|ExposureMask | StructureNotifyMask);
796 //=======================================================================
797 //function : ProcessEvent
799 //=======================================================================
801 void ProcessEvent(Draw_Window& win, XEvent& xev)
803 Standard_Integer X,Y,button;
812 if (xev.xclient.data.l[0] == (int )Draw_DisplayConnection->GetAtom (Aspect_XA_DELETE_WINDOW))
814 // just hide the window
826 button = xev.xbutton.button;
827 win.WButtonPress(X,Y,button);
833 button = xev.xbutton.button;
834 win.WButtonRelease(X,Y,button);
838 XLookupString(&(xev.xkey),
848 win.WMotionNotify(X,Y);
851 case ConfigureNotify :
852 if (win.withWindowManager)
853 win.WConfigureNotify(xev.xconfigure.x, xev.xconfigure.y,
854 xev.xconfigure.width,
855 xev.xconfigure.height);
865 //=======================================================================
868 //=======================================================================
869 void Draw_Window::WExpose()
873 //=======================================================================
874 //function : WButtonPress
876 //=======================================================================
877 void Draw_Window::WButtonPress(const Standard_Integer,
878 const Standard_Integer,
879 const Standard_Integer&)
883 //=======================================================================
884 //function : WButtonRelease
886 //=======================================================================
887 void Draw_Window::WButtonRelease(const Standard_Integer,
888 const Standard_Integer,
889 const Standard_Integer&)
893 /**************************
894 //=======================================================================
895 //function : WKeyPress
897 //=======================================================================
899 void Draw_Window::WKeyPress(char, KeySym&)
902 ***************************/
904 //=======================================================================
905 //function : WMotionNotify
907 //=======================================================================
908 void Draw_Window::WMotionNotify(const Standard_Integer ,
909 const Standard_Integer )
913 //=======================================================================
914 //function : WConfigureNotify
916 //=======================================================================
918 void Draw_Window::WConfigureNotify(const Standard_Integer,
919 const Standard_Integer,
920 const Standard_Integer,
921 const Standard_Integer)
925 //=======================================================================
926 //function : WUnmapNotify
928 //=======================================================================
930 void Draw_Window::WUnmapNotify()
935 //======================================================
936 // funtion : ProcessEvents
937 // purpose : process pending X events
938 //======================================================
940 static void ProcessEvents(ClientData,int)
944 while (XPending(Draw_WindowDisplay)) {
949 XNextEvent(Draw_WindowDisplay,&xev);
951 /* search the window in the window list */
952 Draw_Window* w = Draw_Window::firstWindow;
953 Standard_Integer found=0;
955 if (xev.xany.window == w->win) {
956 ProcessEvent(*w, xev);
963 Tk_HandleEvent(&xev);
968 //======================================================
969 // funtion : GetNextEvent()
971 //======================================================
972 void GetNextEvent(Event& ev)
975 XNextEvent(Draw_WindowDisplay, &xev);
980 ev.window = xev.xbutton.window;
981 ev.button = xev.xbutton.button;
982 ev.x = xev.xbutton.x;
983 ev.y = xev.xbutton.y;
988 ev.window = xev.xmotion.window;
990 ev.x = xev.xmotion.x;
991 ev.y = xev.xmotion.y;
997 //======================================================
998 // funtion :Run_Appli
1000 //======================================================
1003 static Standard_Boolean(*Interprete) (const char*);
1005 void Run_Appli(Standard_Boolean (*interprete) (const char*))
1007 Tcl_Channel outChannel, inChannel ;
1008 Interprete = interprete;
1013 * Commands will come from standard input, so set up an event
1014 * handler for standard input. If the input device is aEvaluate the
1015 * .rc file, if one has been specified, set up an event handler
1016 * for standard input, and print a prompt if the input
1017 * device is a terminal.
1019 inChannel = Tcl_GetStdChannel(TCL_STDIN);
1021 Tcl_CreateChannelHandler(inChannel, TCL_READABLE, StdinProc,
1022 (ClientData) inChannel);
1025 // Create a handler for the draw display
1027 // Adding of the casting into void* to be able to compile on AO1
1028 // ConnectionNumber(Draw_WindowDisplay) is an int 32 bits
1029 // (void*) is a pointer 64 bits ???????
1031 #if !defined(__APPLE__) || defined(MACOSX_USE_GLX)
1032 #if TCL_MAJOR_VERSION < 8
1033 Tk_CreateFileHandler((void*) ConnectionNumber(Draw_WindowDisplay),
1034 TK_READABLE, ProcessEvents,(ClientData) 0 );
1036 Tk_CreateFileHandler(ConnectionNumber(Draw_WindowDisplay),
1037 TK_READABLE, ProcessEvents,(ClientData) 0 );
1043 Draw_Interpretor& aCommands = Draw::GetInterpretor();
1045 if (tty) Prompt(aCommands.Interp(), 0);
1046 Prompt(aCommands.Interp(), 0);
1048 outChannel = Tcl_GetStdChannel(TCL_STDOUT);
1050 Tcl_Flush(outChannel);
1052 Tcl_DStringInit(&command);
1055 * Loop infinitely, waiting for commands to execute. When there
1056 * are no windows left, Tk_MainLoop returns and we exit.
1061 if (Draw_VirtualWindows) {
1062 // main window will never shown
1063 // but main loop will parse all Xlib messages
1064 Tcl_Eval(aCommands.Interp(), "wm withdraw .");
1071 Standard_Integer count = ConnectionNumber(Draw_WindowDisplay);
1072 Standard_Integer numfd;
1076 FD_SET(count,&readset);
1078 numfd = select(count+1,(Integer*)&readset,NULL,NULL,NULL);
1080 numfd = select(count+1,&readset,NULL,NULL,NULL);
1082 if (FD_ISSET(0,&readset)) StdinProc((ClientData)0,0);
1083 if (FD_ISSET(count,&readset)) ProcessEvents((ClientData)0,0);
1087 NCollection_List<Draw_Window::FCallbackBeforeTerminate>::Iterator Iter(MyCallbacks);
1088 for(; Iter.More(); Iter.Next())
1094 //======================================================
1095 // funtion : Init_Appli()
1097 //======================================================
1098 Standard_Boolean Init_Appli()
1100 Draw_Interpretor& aCommands = Draw::GetInterpretor();
1102 Tcl_Interp *interp = aCommands.Interp();
1108 } catch (Standard_Failure const&) {
1109 std::cout <<" Pb au lancement de TK_Init "<<std::endl;
1112 Tcl_StaticPackage(interp, "Tk", Tk_Init, (Tcl_PackageInitProc *) NULL);
1114 Tk_Window aMainWindow = Tk_MainWindow(interp) ;
1115 if (aMainWindow == NULL) {
1116 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
1117 fprintf(stderr, "%s\n", Tcl_GetStringResult(interp));
1119 fprintf(stderr, "%s\n", interp->result);
1123 #if defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1124 Tk_SetAppName(aMainWindow, "Draw");
1126 Tk_Name(aMainWindow) = Tk_GetUid(Tk_SetAppName(aMainWindow, "Draw"));
1129 Tk_GeometryRequest (aMainWindow, 200, 200);
1131 #if !defined(__APPLE__) || defined(MACOSX_USE_GLX)
1132 if (Draw_DisplayConnection.IsNull())
1136 Draw_DisplayConnection = new Aspect_DisplayConnection();
1138 catch (Standard_Failure const&)
1140 std::cout << "Cannot open display. Interpret commands in batch mode." << std::endl;
1141 return Standard_False;
1144 if (Draw_WindowDisplay == NULL)
1146 Draw_WindowDisplay = Draw_DisplayConnection->GetDisplay();
1149 // synchronize the display server : could be done within Tk_Init
1151 XSynchronize(Draw_WindowDisplay, True);
1152 XSetInputFocus(Draw_WindowDisplay,
1154 RevertToPointerRoot,
1157 Draw_WindowScreen = DefaultScreen(Draw_WindowDisplay);
1158 Draw_WindowColorMap = DefaultColormap(Draw_WindowDisplay,
1163 Tcl_SetVar(interp,"tcl_interactive",(char*)(tty ? "1" : "0"), TCL_GLOBAL_ONLY);
1164 // Tcl_SetVar(interp,"tcl_interactive",tty ? "1" : "0", TCL_GLOBAL_ONLY);
1165 return Standard_True;
1168 //======================================================
1169 // funtion : Destroy_Appli()
1171 //======================================================
1172 void Destroy_Appli()
1174 //XCloseDisplay(Draw_WindowDisplay);
1178 *----------------------------------------------------------------------
1182 * This procedure is invoked by the event dispatcher whenever
1183 * standard input becomes readable. It grabs the next line of
1184 * input characters, adds them to a command being assembled, and
1185 * executes the command if it's complete.
1191 * Could be almost arbitrary, depending on the command that's
1194 *----------------------------------------------------------------------
1198 //static void StdinProc(ClientData clientData, int mask)
1199 static void StdinProc(ClientData clientData, int )
1201 static int gotPartial = 0;
1205 Tcl_Channel chan = (Tcl_Channel) clientData;
1207 // MSV Nov 2, 2001: patch for TCL 8.3: initialize line to avoid exception
1208 // when first user input is an empty string
1209 Tcl_DStringFree(&line);
1210 count = Tcl_Gets(chan, &line);
1213 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)))
1214 Tcl_DString linetmp;
1215 Tcl_DStringInit(&linetmp);
1216 Tcl_UniChar * UniCharString;
1217 UniCharString = Tcl_UtfToUniCharDString(Tcl_DStringValue(&line),-1,&linetmp);
1218 Standard_Integer l = Tcl_UniCharLen(UniCharString);
1219 TCollection_AsciiString AsciiString("");
1220 Standard_Character Character;
1222 for (i=0; i<l; i++) {
1223 Character = UniCharString[i];
1224 AsciiString.AssignCat(Character);
1226 Tcl_DStringInit(&line);
1227 Tcl_DStringAppend(&line, AsciiString.ToCString(), -1);
1234 Tcl_DeleteChannelHandler(chan, StdinProc, (ClientData) chan);
1242 (void) Tcl_DStringAppend(&command, Tcl_DStringValue(&line), -1);
1243 cmd = Tcl_DStringAppend(&command, "\n", -1);
1244 Tcl_DStringFree(&line);
1247 if (!Tcl_CommandComplete(cmd)) {
1254 * Disable the stdin channel handler while evaluating the command;
1255 * otherwise if the command re-enters the event loop we might
1256 * process commands from stdin before the current command is
1257 * finished. Among other things, this will trash the text of the
1258 * command being evaluated.
1261 Tcl_CreateChannelHandler(chan, 0, StdinProc, (ClientData) chan);
1265 * Disable the stdin file handler while evaluating the command;
1266 * otherwise if the command re-enters the event loop we might
1267 * process commands from stdin before the current command is
1268 * finished. Among other things, this will trash the text of the
1269 * command being evaluated.
1273 // Tk_CreateFileHandler(0, 0, StdinProc, (ClientData) 0);
1276 // xab average to avoid an output SIGBUS of DRAW
1277 // to ultimately prescise or remove once
1278 // the problem of free on the global variable at the average
1285 Tcl_CreateChannelHandler(chan, TCL_READABLE, StdinProc,
1287 Tcl_DStringFree(&command);
1294 if (tty) Prompt(Draw::GetInterpretor().Interp(), gotPartial);
1296 } catch (Standard_Failure const&) {}
1302 // Source Specifique WNT
1304 /****************************************************\
1307 \****************************************************/
1309 #include "Draw_Window.hxx"
1310 #include "DrawRessource.h"
1313 #include <Draw_Appli.hxx>
1320 // Position of information in the extra memory
1322 // indicates SUBSYSTEM:CONSOLE linker option, to be set to True in main()
1324 Standard_Boolean Draw_IsConsoleSubsystem = Standard_False;
1327 Standard_Boolean Draw_BlackBackGround = Standard_True;
1329 // Creation of color stylos
1330 HPEN colorPenTab[MAXCOLOR] = {CreatePen(PS_SOLID, PENWIDTH, RGB(255,255,255)),
1331 CreatePen(PS_SOLID, PENWIDTH, RGB(255,0,0)),
1332 CreatePen(PS_SOLID, PENWIDTH, RGB(0,255,0)),
1333 CreatePen(PS_SOLID, PENWIDTH, RGB(0,0,255)),
1334 CreatePen(PS_SOLID, PENWIDTH, RGB(0,255,255)),
1335 CreatePen(PS_SOLID, PENWIDTH, RGB(255,215,0)),
1336 CreatePen(PS_SOLID, PENWIDTH, RGB(255,0,255)),
1337 CreatePen(PS_SOLID, PENWIDTH, RGB(255,52,179)),
1338 CreatePen(PS_SOLID, PENWIDTH, RGB(255,165,0)),
1339 CreatePen(PS_SOLID, PENWIDTH, RGB(255,228,225)),
1340 CreatePen(PS_SOLID, PENWIDTH, RGB(255,160,122)),
1341 CreatePen(PS_SOLID, PENWIDTH, RGB(199,21,133)),
1342 CreatePen(PS_SOLID, PENWIDTH, RGB(255,255,0)),
1343 CreatePen(PS_SOLID, PENWIDTH, RGB(240,230,140)),
1344 CreatePen(PS_SOLID, PENWIDTH, RGB(255,127,80))};
1346 // Correspondance mode X11 and WINDOWS NT
1347 int modeTab[16] = {R2_BLACK, R2_MASKPEN, R2_MASKPENNOT, R2_COPYPEN,
1348 R2_MASKNOTPEN, R2_NOP, R2_XORPEN, R2_MERGEPEN,
1349 R2_NOTMASKPEN, R2_NOTXORPEN, R2_NOT, R2_MERGEPENNOT,
1350 R2_NOTCOPYPEN, R2_MERGENOTPEN, R2_NOTMERGEPEN, R2_WHITE};
1352 /*--------------------------------------------------------*\
1353 | CREATE DRAW WINDOW PROCEDURE
1354 \*--------------------------------------------------------*/
1355 HWND DrawWindow::CreateDrawWindow(HWND hWndClient, int nitem)
1357 if (Draw_IsConsoleSubsystem) {
1358 HWND aWin = CreateWindowW (DRAWCLASS, DRAWTITLE,
1359 WS_OVERLAPPEDWINDOW,
1361 NULL, NULL,::GetModuleHandle(NULL), NULL);
1362 if (!Draw_VirtualWindows)
1364 SetWindowPos(aWin, HWND_TOPMOST, 1,1,1,1, SWP_NOMOVE);
1365 SetWindowPos(aWin, HWND_NOTOPMOST, 1,1,1,1, SWP_NOMOVE);
1370 HANDLE hInstance = (HANDLE )GetWindowLongPtrW (hWndClient, GWLP_HINSTANCE);
1372 return CreateMDIWindowW(DRAWCLASS, DRAWTITLE,
1373 WS_CAPTION | WS_CHILD | WS_THICKFRAME,
1375 hWndClient, (HINSTANCE)hInstance, nitem);
1380 /*--------------------------------------------------------*\
1381 | DRAW WINDOW PROCEDURE
1382 \*--------------------------------------------------------*/
1383 LRESULT APIENTRY DrawWindow::DrawProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
1385 DrawWindow* localObjet = (DrawWindow* )GetWindowLongPtrW (hWnd, CLIENTWND);
1388 return Draw_IsConsoleSubsystem
1389 ? DefWindowProcW (hWnd, wMsg, wParam, lParam)
1390 : DefMDIChildProcW (hWnd, wMsg, wParam, lParam);
1398 return 0; // do nothing - window destruction should be performed by application
1403 BeginPaint (hWnd, &ps);
1404 if (localObjet->GetUseBuffer())
1406 localObjet->Redraw();
1410 localObjet->WExpose();
1412 EndPaint (hWnd, &ps);
1417 if (localObjet->GetUseBuffer())
1419 localObjet->InitBuffer();
1420 localObjet->WExpose();
1421 localObjet->Redraw();
1427 return Draw_IsConsoleSubsystem
1428 ? DefWindowProcW (hWnd, wMsg, wParam, lParam)
1429 : DefMDIChildProcW (hWnd, wMsg, wParam, lParam);
1435 ** IMPLEMENTATION of the CLASS DRAWWINDOW
1438 /*--------------------------------------------------------*\
1439 | Initialization of static variables of DrawWindow
1440 \*--------------------------------------------------------*/
1442 DrawWindow* DrawWindow::firstWindow = NULL;
1443 HWND DrawWindow::hWndClientMDI = 0;
1445 /*--------------------------------------------------------*\
1446 | Constructors of Draw_Window
1447 \*--------------------------------------------------------*/
1449 // Default Constructor
1450 //________________________
1451 DrawWindow::DrawWindow() :
1456 myUseBuffer(Standard_False)
1458 if (firstWindow) firstWindow->previous = this;
1462 //________________________
1463 DrawWindow::DrawWindow(const char* title,
1464 Standard_Integer X, Standard_Integer Y,
1465 Standard_Integer dX,Standard_Integer dY) :
1466 win(0), next(firstWindow), previous(NULL), myMemHbm(NULL), myUseBuffer(Standard_False)
1468 if (firstWindow) firstWindow->previous = this;
1473 DrawWindow::DrawWindow(const char* title,
1474 Standard_Integer X, Standard_Integer Y,
1475 Standard_Integer dX,Standard_Integer dY,
1477 win(theWin),next(firstWindow), previous(NULL), myMemHbm(NULL), myUseBuffer(Standard_False)
1479 if (firstWindow) firstWindow->previous = this;
1487 /*--------------------------------------------------------*\
1488 | Destructor of DrawWindow
1489 \*--------------------------------------------------------*/
1490 DrawWindow::~DrawWindow()
1493 previous->next = next;
1497 next->previous = previous;
1499 // Delete 'off-screen drawing'-related objects
1501 DeleteObject(myMemHbm);
1508 /*--------------------------------------------------------*\
1510 \*--------------------------------------------------------*/
1511 void DrawWindow::Init(Standard_Integer theXLeft, Standard_Integer theYTop,
1512 Standard_Integer theWidth, Standard_Integer theHeight)
1516 win = CreateDrawWindow(hWndClientMDI, 0);
1519 // include decorations in the window dimensions
1520 // to reproduce same behaviour of Xlib window.
1521 DWORD aWinStyle = GetWindowLongW (win, GWL_STYLE);
1522 DWORD aWinStyleEx = GetWindowLongW (win, GWL_EXSTYLE);
1523 HMENU aMenu = GetMenu (win);
1526 aRect.top = theYTop;
1527 aRect.bottom = theYTop + theHeight;
1528 aRect.left = theXLeft;
1529 aRect.right = theXLeft + theWidth;
1530 AdjustWindowRectEx (&aRect, aWinStyle, aMenu != NULL ? TRUE : FALSE, aWinStyleEx);
1532 SetPosition (aRect.left, aRect.top);
1533 SetDimension (aRect.right - aRect.left, aRect.bottom - aRect.top);
1534 // Save the pointer at the instance associated to the window
1535 SetWindowLongPtrW (win, CLIENTWND, (LONG_PTR)this);
1536 HDC hDC = GetDC(win);
1537 SetBkColor(hDC, RGB(0, 0, 0));
1540 SelectObject(hDC, colorPenTab[myCurrPen]); // Default pencil
1541 SelectObject(hDC, GetStockObject(BLACK_BRUSH));
1542 SetTextColor(hDC, RGB(0,0,255));
1543 ReleaseDC(win, hDC);
1545 if (Draw_VirtualWindows)
1547 // create a virtual window
1548 SetUseBuffer (Standard_True);
1552 /*--------------------------------------------------------*\
1554 \*--------------------------------------------------------*/
1555 void DrawWindow::SetUseBuffer(Standard_Boolean use)
1561 /*--------------------------------------------------------*\
1563 \*--------------------------------------------------------*/
1564 void DrawWindow::InitBuffer()
1568 HDC hDC = GetDC(win);
1569 GetClientRect(win, &rc);
1572 GetObjectW (myMemHbm, sizeof(BITMAP), &aBmp);
1573 if (rc.right-rc.left == aBmp.bmWidth && rc.bottom-rc.top == aBmp.bmHeight) return;
1574 DeleteObject(myMemHbm);
1576 myMemHbm = (HBITMAP)CreateCompatibleBitmap(hDC,
1579 HDC aMemDC = GetMemDC(hDC);
1580 FillRect(aMemDC, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
1581 ReleaseMemDC(aMemDC);
1582 ReleaseDC(win, hDC);
1586 DeleteObject(myMemHbm);
1592 /*--------------------------------------------------------*\
1594 \*--------------------------------------------------------*/
1595 HDC DrawWindow::GetMemDC(HDC theWinDC)
1597 if (!myUseBuffer) return NULL;
1599 HDC aWorkDC = CreateCompatibleDC(theWinDC);
1600 myOldHbm = (HBITMAP)SelectObject(aWorkDC, myMemHbm);
1601 SetROP2(aWorkDC, modeTab[myCurrMode]);
1602 SelectObject(aWorkDC, colorPenTab[myCurrPen]);
1603 SetBkColor(aWorkDC, RGB(0, 0, 0));
1604 SelectObject(aWorkDC, GetStockObject(BLACK_BRUSH));
1605 SetTextColor(aWorkDC, RGB(0,0,255));
1610 /*--------------------------------------------------------*\
1612 \*--------------------------------------------------------*/
1613 void DrawWindow::ReleaseMemDC(HDC theMemDC)
1615 if (!myUseBuffer || !theMemDC) return;
1617 if (myOldHbm) SelectObject(theMemDC, myOldHbm);
1622 /*--------------------------------------------------------*\
1624 \*--------------------------------------------------------*/
1625 void DrawWindow::SetPosition(Standard_Integer posX, Standard_Integer posY)
1627 UINT aFlags = SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER;
1628 if (Draw_VirtualWindows)
1630 aFlags |= SWP_NOSENDCHANGING;
1632 SetWindowPos (win, 0, posX, posY, 0, 0, aFlags);
1636 /*--------------------------------------------------------*\
1638 \*--------------------------------------------------------*/
1639 void DrawWindow::SetDimension(Standard_Integer dimX, Standard_Integer dimY)
1641 UINT aFlags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER;
1642 if (Draw_VirtualWindows)
1644 aFlags |= SWP_NOSENDCHANGING;
1646 SetWindowPos (win, 0, 0, 0, dimX, dimY, aFlags);
1650 /*--------------------------------------------------------*\
1652 \*--------------------------------------------------------*/
1653 void DrawWindow::GetPosition(Standard_Integer &dimX,
1654 Standard_Integer &dimY)
1657 GetWindowRect(win, &rect);
1660 point.x = rect.left;
1663 ScreenToClient(hWndClientMDI, &point);
1669 /*--------------------------------------------------------*\
1671 \*--------------------------------------------------------*/
1672 Standard_Integer DrawWindow::HeightWin() const
1675 GetClientRect(win, &rect);
1676 return(rect.bottom-rect.top);
1680 /*--------------------------------------------------------*\
1682 \*--------------------------------------------------------*/
1683 Standard_Integer DrawWindow::WidthWin() const
1686 GetClientRect(win, &rect);
1687 return(rect.right-rect.left);
1691 /*--------------------------------------------------------*\
1693 \*--------------------------------------------------------*/
1694 void DrawWindow::SetTitle (const TCollection_AsciiString& theTitle)
1696 const TCollection_ExtendedString aTitleW (theTitle);
1697 SetWindowTextW (win, aTitleW.ToWideString());
1701 /*--------------------------------------------------------*\
1703 \*--------------------------------------------------------*/
1704 TCollection_AsciiString DrawWindow::GetTitle() const
1706 wchar_t aTitleW[32];
1707 GetWindowTextW (win, aTitleW, 30);
1708 return TCollection_AsciiString (aTitleW);
1711 //=======================================================================
1712 //function : IsMapped
1714 //=======================================================================
1715 bool Draw_Window::IsMapped() const
1717 if (Draw_VirtualWindows
1723 LONG aWinStyle = GetWindowLongW (win, GWL_STYLE);
1724 return (aWinStyle & WS_VISIBLE) != 0
1725 && (aWinStyle & WS_MINIMIZE) == 0;
1728 /*--------------------------------------------------------*\
1730 \*--------------------------------------------------------*/
1731 void DrawWindow::DisplayWindow()
1733 if (Draw_VirtualWindows)
1737 ShowWindow (win, SW_SHOW);
1742 /*--------------------------------------------------------*\
1744 \*--------------------------------------------------------*/
1745 void DrawWindow::Hide()
1747 ShowWindow(win, SW_HIDE);
1751 /*--------------------------------------------------------*\
1753 \*--------------------------------------------------------*/
1754 void DrawWindow::Destroy()
1761 /*--------------------------------------------------------*\
1763 \*--------------------------------------------------------*/
1764 void DrawWindow::Clear()
1766 HDC hDC = GetDC(win);
1767 HDC aWorkDC = myUseBuffer ? GetMemDC(hDC) : hDC;
1770 SelectObject(aWorkDC,GetStockObject(BLACK_PEN));
1771 Rectangle(aWorkDC, 0, 0, WidthWin(), HeightWin());
1772 RestoreDC(aWorkDC,-1);
1774 if (myUseBuffer) ReleaseMemDC(aWorkDC);
1778 /*--------------------------------------------------------*\
1780 \*--------------------------------------------------------*/
1781 static Standard_Boolean SaveBitmap (HBITMAP theHBitmap,
1782 const char* theFileName)
1784 // Get informations about the bitmap
1786 if (GetObjectW (theHBitmap, sizeof(BITMAP), &aBitmap) == 0)
1788 return Standard_False;
1791 Image_AlienPixMap anImage;
1792 const Standard_Size aSizeRowBytes = ((Standard_Size(aBitmap.bmWidth) * 24 + 31) / 32) * 4; // 4 bytes alignment for GetDIBits()
1793 if (!anImage.InitTrash (Image_Format_BGR, Standard_Size(aBitmap.bmWidth), Standard_Size(aBitmap.bmHeight), aSizeRowBytes))
1795 return Standard_False;
1797 anImage.SetTopDown (false);
1800 BITMAPINFOHEADER aBitmapInfo;
1801 memset (&aBitmapInfo, 0, sizeof(BITMAPINFOHEADER));
1802 aBitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
1803 aBitmapInfo.biWidth = aBitmap.bmWidth;
1804 aBitmapInfo.biHeight = aBitmap.bmHeight; // positive means bottom-up!
1805 aBitmapInfo.biPlanes = 1;
1806 aBitmapInfo.biBitCount = 24;
1807 aBitmapInfo.biCompression = BI_RGB;
1810 HDC aDC = GetDC (NULL);
1811 Standard_Boolean isSuccess = GetDIBits (aDC, theHBitmap,
1812 0, // first scan line to set
1813 aBitmap.bmHeight, // number of scan lines to copy
1814 anImage.ChangeData(), // array for bitmap bits
1815 (LPBITMAPINFO )&aBitmapInfo, // bitmap data info
1816 DIB_RGB_COLORS) != 0;
1817 ReleaseDC (NULL, aDC);
1818 return isSuccess && anImage.Save (theFileName);
1821 /*--------------------------------------------------------*\
1823 \*--------------------------------------------------------*/
1824 Standard_Boolean DrawWindow::Save (const char* theFileName) const
1828 return SaveBitmap (myMemHbm, theFileName);
1832 GetClientRect (win, &aRect);
1833 int aWidth = aRect.right - aRect.left;
1834 int aHeight = aRect.bottom - aRect.top;
1837 HDC aDstDC = GetDC (NULL);
1838 HDC aSrcDC = GetDC (win); // we copy only client area
1839 HDC aMemDC = CreateCompatibleDC (aDstDC);
1841 // Copy the screen to the bitmap
1842 HBITMAP anHBitmapDump = CreateCompatibleBitmap (aDstDC, aWidth, aHeight);
1843 HBITMAP anHBitmapOld = (HBITMAP )SelectObject (aMemDC, anHBitmapDump);
1844 BitBlt (aMemDC, 0, 0, aWidth, aHeight, aSrcDC, 0, 0, SRCCOPY);
1846 Standard_Boolean isSuccess = SaveBitmap (anHBitmapDump, theFileName);
1849 DeleteObject (SelectObject (aMemDC, anHBitmapOld));
1855 /*--------------------------------------------------------*\
1857 \*--------------------------------------------------------*/
1858 void DrawWindow::DrawString(int x,int y, char* text)
1860 HDC hDC = GetDC(win);
1861 HDC aWorkDC = myUseBuffer ? GetMemDC(hDC) : hDC;
1863 TCollection_ExtendedString textW (text);
1864 TextOutW(aWorkDC, x, y, (const wchar_t*)textW.ToExtString(), (int )strlen(text));
1866 if (myUseBuffer) ReleaseMemDC(aWorkDC);
1870 /*--------------------------------------------------------*\
1872 \*--------------------------------------------------------*/
1873 void DrawWindow::DrawSegments(Segment *tab, int nbElem)
1875 HDC hDC = GetDC(win);
1876 HDC aWorkDC = myUseBuffer ? GetMemDC(hDC) : hDC;
1878 for(int i = 0 ; i < nbElem ; i++)
1880 MoveToEx(aWorkDC, tab[i].x1, tab[i].y1, NULL);
1881 LineTo(aWorkDC, tab[i].x2, tab[i].y2);
1884 if (myUseBuffer) ReleaseMemDC(aWorkDC);
1888 /*--------------------------------------------------------*\
1890 \*--------------------------------------------------------*/
1891 void DrawWindow::Redraw()
1894 HDC hDC = GetDC(win);
1896 GetClientRect(win, &rc);
1897 HDC aMemDC = GetMemDC(hDC);
1900 rc.right-rc.left, rc.bottom-rc.top,
1903 ReleaseMemDC(aMemDC);
1908 /*--------------------------------------------------------*\
1910 \*--------------------------------------------------------*/
1911 void DrawWindow::SetMode(int mode)
1913 HDC hDC = GetDC(win);
1915 SetROP2(hDC, modeTab[mode]);
1920 /*--------------------------------------------------------*\
1922 \*--------------------------------------------------------*/
1923 void DrawWindow::SetColor(Standard_Integer color)
1925 HDC hDC = GetDC(win);
1927 SelectObject(hDC,colorPenTab[color]);
1932 /*--------------------------------------------------------*\
1934 \*--------------------------------------------------------*/
1935 void DrawWindow::WExpose()
1940 /*--------------------------------------------------------*\
1942 \*--------------------------------------------------------*/
1943 void DrawWindow::WButtonPress(const Standard_Integer,
1944 const Standard_Integer,
1945 const Standard_Integer&)
1950 /*--------------------------------------------------------*\
1952 \*--------------------------------------------------------*/
1953 void DrawWindow::WButtonRelease(const Standard_Integer,
1954 const Standard_Integer,
1955 const Standard_Integer&)
1960 /*--------------------------------------------------------*\
1962 \*--------------------------------------------------------*/
1963 void Draw_Window::WMotionNotify(const Standard_Integer ,
1964 const Standard_Integer )
1969 /*--------------------------------------------------------*\
1971 \*--------------------------------------------------------*/
1972 void DrawWindow::WConfigureNotify(const Standard_Integer,
1973 const Standard_Integer,
1974 const Standard_Integer,
1975 const Standard_Integer)
1980 /*--------------------------------------------------------*\
1982 \*--------------------------------------------------------*/
1983 void DrawWindow::WUnmapNotify()
1990 ** IMPLEMENTATION of the CLASS SEGMENT
1993 /*--------------------------------------------------------*\
1995 \*--------------------------------------------------------*/
1997 void Segment::Init(Standard_Integer a1, Standard_Integer a2,
1998 Standard_Integer a3, Standard_Integer a4)
2006 static DWORD WINAPI tkLoop (LPVOID theThreadParameter);
2008 static Tk_Window mainWindow;
2011 //* threads sinchronization *//
2012 DWORD dwMainThreadId;
2013 console_semaphore_value volatile console_semaphore = WAIT_CONSOLE_COMMAND;
2014 wchar_t console_command[DRAW_COMMAND_SIZE + 1];
2015 bool volatile isTkLoopStarted = false;
2017 /*--------------------------------------------------------*\
2019 \*--------------------------------------------------------*/
2020 Standard_Boolean Init_Appli(HINSTANCE hInst,
2021 HINSTANCE hPrevInst, int nShow, HWND& hWndFrame )
2025 console_semaphore = STOP_CONSOLE;
2027 dwMainThreadId = GetCurrentThreadId();
2029 //necessary for normal Tk operation
2030 hThread = CreateThread (NULL, // no security attributes
2031 0, // use default stack size
2032 tkLoop, // thread function
2033 NULL, // no thread function argument
2034 0, // use default creation flags
2037 std::cout << "Failed to create Tcl/Tk main loop thread. Switching to batch mode..." << std::endl;
2038 Draw_Batch = Standard_True;
2039 Draw_Interpretor& aCommands = Draw::GetInterpretor();
2041 Tcl_Interp *interp = aCommands.Interp();
2047 } catch (Standard_Failure& anExcept) {
2048 std::cout << "Failed to initialize Tk: " << anExcept.GetMessageString() << std::endl;
2051 Tcl_StaticPackage(interp, "Tk", Tk_Init, (Tcl_PackageInitProc *) NULL);
2053 //since the main Tcl/Tk loop wasn't created --> switch to batch mode
2054 return Standard_False;
2057 // san - 06/08/2002 - Time for tkLoop to start; Tk fails to initialize otherwise
2058 while (!isTkLoopStarted)
2061 // Saving of window classes
2063 if(!RegisterAppClass(hInst))
2064 return(Standard_False);
2067 ** Enter the application message-polling loop. This is the anchor for
2070 hWndFrame = !Draw_IsConsoleSubsystem ? CreateAppWindow (hInst) : NULL;
2071 if (hWndFrame != NULL)
2073 ShowWindow(hWndFrame,nShow);
2074 UpdateWindow(hWndFrame);
2077 return Standard_True;
2080 Standard_Boolean Draw_Interprete (const char*);
2082 /*--------------------------------------------------------*\
2083 | readStdinThreadFunc
2084 \*--------------------------------------------------------*/
2085 static DWORD WINAPI readStdinThreadFunc (const LPVOID theThreadParameter)
2087 (void)theThreadParameter;
2088 if (!Draw_IsConsoleSubsystem)
2093 // Console locale could be set to the system codepage .OCP (UTF-8 is not properly supported on Windows).
2094 // However, to use it, we have to care using std::wcerr/fwprintf/WriteConsoleW for non-ascii strings everywhere (including Tcl itself),
2095 // or otherwise we can have incomplete output issues
2096 // (e.g. UNICODE string will be NOT just corrupted as in case when we don't set setlocale()
2097 // but will break further normal output to console due to special characters being accidentally handled by console in the wrong way).
2098 //setlocale (LC_ALL, ".OCP");
2100 // _O_U16TEXT can be used with fgetws() to get similar result as ReadConsoleW() without affecting setlocale(),
2101 // however it would break pipe input
2102 //_setmode (_fileno(stdin), _O_U16TEXT);
2104 bool isConsoleInput = true;
2107 while (console_semaphore != WAIT_CONSOLE_COMMAND)
2112 const HANDLE anStdIn = ::GetStdHandle (STD_INPUT_HANDLE);
2114 && anStdIn != INVALID_HANDLE_VALUE
2118 if (ReadConsoleW (anStdIn, console_command, DRAW_COMMAND_SIZE, &aNbRead, NULL))
2120 console_command[aNbRead] = L'\0';
2121 console_semaphore = HAS_CONSOLE_COMMAND;
2126 const DWORD anErr = GetLastError();
2127 if (anErr != ERROR_SUCCESS)
2129 // fallback using fgetws() which would work with pipes
2130 // but supports Unicode only through multi-byte encoding (which is not UTF-8)
2131 isConsoleInput = false;
2137 // fgetws() works only for characters within active locale (see setlocale())
2138 if (fgetws (console_command, DRAW_COMMAND_SIZE, stdin))
2140 console_semaphore = HAS_CONSOLE_COMMAND;
2145 /*--------------------------------------------------------*\
2146 | exitProc: finalization handler for Tcl/Tk thread. Forces parent process to die
2147 \*--------------------------------------------------------*/
2148 void exitProc(ClientData /*dc*/)
2150 NCollection_List<Draw_Window::FCallbackBeforeTerminate>::Iterator Iter(MyCallbacks);
2151 for(; Iter.More(); Iter.Next())
2155 HANDLE proc = GetCurrentProcess();
2156 TerminateProcess(proc, 0);
2159 // This is fixed version of TclpGetDefaultStdChannel() defined in tclWinChan.c
2160 // See https://core.tcl.tk/tcl/tktview/91c9bc1c457fda269ae18595944fc3c2b54d961d
2162 TclpGetDefaultStdChannel(
2163 int type) /* One of TCL_STDIN, TCL_STDOUT, or
2166 Tcl_Channel channel;
2169 const char *bufMode = NULL;
2170 DWORD handleId = (DWORD) -1;
2171 /* Standard handle to retrieve. */
2175 handleId = STD_INPUT_HANDLE;
2176 mode = TCL_READABLE;
2180 handleId = STD_OUTPUT_HANDLE;
2181 mode = TCL_WRITABLE;
2185 handleId = STD_ERROR_HANDLE;
2186 mode = TCL_WRITABLE;
2190 Tcl_Panic("TclGetDefaultStdChannel: Unexpected channel type");
2194 handle = GetStdHandle(handleId);
2197 * Note that we need to check for 0 because Windows may return 0 if this
2198 * is not a console mode application, even though this is not a valid
2202 if ((handle == INVALID_HANDLE_VALUE) || (handle == 0)) {
2203 return (Tcl_Channel) NULL;
2207 * Make duplicate of the standard handle as it may be altered
2208 * (closed, reopened with another type of the object etc.) by
2209 * the system or a user code at any time, e.g. by call to _dup2()
2211 if (! DuplicateHandle (GetCurrentProcess(), handle,
2212 GetCurrentProcess(), &handle,
2213 0, FALSE, DUPLICATE_SAME_ACCESS)) {
2214 return (Tcl_Channel) NULL;
2217 channel = Tcl_MakeFileChannel(handle, mode);
2219 if (channel == NULL) {
2220 return (Tcl_Channel) NULL;
2224 * Set up the normal channel options for stdio handles.
2227 if (Tcl_SetChannelOption(NULL,channel,"-translation","auto")!=TCL_OK ||
2228 Tcl_SetChannelOption(NULL,channel,"-eofchar","\032 {}")!=TCL_OK ||
2229 Tcl_SetChannelOption(NULL,channel,"-buffering",bufMode)!=TCL_OK) {
2230 Tcl_Close(NULL, channel);
2231 return (Tcl_Channel) NULL;
2237 static void ResetStdChannel (int type)
2239 Tcl_Channel aChannel = TclpGetDefaultStdChannel (type);
2240 Tcl_SetStdChannel (aChannel, type);
2243 Tcl_RegisterChannel (NULL, aChannel);
2247 /*--------------------------------------------------------*\
2248 | tkLoop: implements Tk_Main()-like behaviour in a separate thread
2249 \*--------------------------------------------------------*/
2250 static DWORD WINAPI tkLoop (const LPVOID theThreadParameter)
2252 (void)theThreadParameter;
2253 Tcl_CreateExitHandler(exitProc, 0);
2255 Draw_Interpretor& aCommands = Draw::GetInterpretor();
2257 Tcl_Interp *interp = aCommands.Interp();
2260 // Work-around against issue with Tcl standard channels on Windows.
2261 // These channels by default use OS handles owned by the system which
2262 // may get invalidated e.g. by dup2() (see dlog command).
2263 // If this happens, output to stdout from Tcl (e.g. puts) gets broken
2264 // (sympthom is error message: "error writing "stdout": bad file number").
2265 // To prevent this, we set standard channels using duplicate of system handles.
2266 // The effect is that Tcl channel becomes independent on C file descriptor
2267 // and even if stdout/stderr are redirected using dup2(), Tcl keeps using
2269 ResetStdChannel (TCL_STDOUT);
2270 ResetStdChannel (TCL_STDERR);
2272 #if (TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5))
2273 // Plain Tcl (8.6.4+) initializes interpretor channels automatically, but
2274 // ActiveState Tcl (at least 8.6.4) does not seem to do that, so channels
2275 // need to be set into interpretor explicitly
2277 Tcl_Channel aChannelIn = Tcl_GetStdChannel (TCL_STDIN);
2278 Tcl_Channel aChannelOut = Tcl_GetStdChannel (TCL_STDOUT);
2279 Tcl_Channel aChannelErr = Tcl_GetStdChannel (TCL_STDERR);
2280 if (aChannelIn != NULL)
2282 Tcl_RegisterChannel (aCommands.Interp(), aChannelIn);
2284 if (aChannelOut != NULL)
2286 Tcl_RegisterChannel (aCommands.Interp(), aChannelOut);
2288 if (aChannelErr != NULL)
2290 Tcl_RegisterChannel (aCommands.Interp(), aChannelErr);
2296 // initialize the Tk library if not in 'virtual windows' mode
2297 // (virtual windows are created by OCCT with native APIs,
2298 // thus Tk will be useless)
2299 if (!Draw_VirtualWindows)
2304 Standard_Integer res = Tk_Init (interp);
2307 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
2308 std::cout << "tkLoop: error in Tk initialization. Tcl reported: " << Tcl_GetStringResult(interp) << std::endl;
2310 std::cout << "tkLoop: error in Tk initialization. Tcl reported: " << interp->result << std::endl;
2314 catch (const Standard_Failure&)
2316 std::cout << "tkLoop: exception in TK_Init\n";
2318 Tcl_StaticPackage (interp, "Tk", Tk_Init, (Tcl_PackageInitProc* ) NULL);
2319 mainWindow = Tk_MainWindow (interp);
2320 if (mainWindow == NULL)
2322 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
2323 fprintf (stderr, "%s\n", Tcl_GetStringResult(interp));
2325 fprintf (stderr, "%s\n", interp->result);
2327 std::cout << "tkLoop: Tk_MainWindow() returned NULL. Exiting...\n";
2330 Tk_Name(mainWindow) = Tk_GetUid (Tk_SetAppName (mainWindow, "Draw"));
2334 // set signal handler in the new thread
2335 OSD::SetSignal(Standard_False);
2337 // inform the others that we have started
2338 isTkLoopStarted = true;
2340 while (console_semaphore == STOP_CONSOLE)
2341 Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT);
2343 if (Draw_IsConsoleSubsystem && console_semaphore == WAIT_CONSOLE_COMMAND)
2347 Standard_Boolean toLoop = Standard_True;
2350 // The natural way is first flushing events, already put into queue, and then processing custom code in-between.
2351 // Unfortunately, Tcl has no API returning the number of queued events like XPending(), and only empty state can be checked.
2352 // Since events can be continuously fed from parallel threads, Tcl_DoOneEvent might never return empty state at all.
2353 const bool isTclEventQueueEmpty = Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT) == 0;
2354 if (console_semaphore == HAS_CONSOLE_COMMAND)
2356 const TCollection_AsciiString aCmdUtf8 (console_command);
2357 const bool wasInterpreted = Draw_Interprete (aCmdUtf8.ToCString());
2358 if (Draw_IsConsoleSubsystem)
2360 Prompt (interp, wasInterpreted ? 0 : 1);
2362 console_semaphore = WAIT_CONSOLE_COMMAND;
2364 else if (isTclEventQueueEmpty)
2366 // release CPU while polling
2370 // We should not exit until the Main Tk window is closed
2371 toLoop = (Draw_VirtualWindows || Tk_GetNumMainWindows() > 0);
2379 /*--------------------------------------------------------*\
2381 \*--------------------------------------------------------*/
2382 void Run_Appli(HWND hWnd)
2385 HACCEL hAccel = NULL;
2389 // if (!(hAccel = LoadAccelerators (hInstance, MAKEINTRESOURCE(ACCEL_ID))))
2390 // MessageBox(hWnd, "MDI: Load Accel failure!", "Error", MB_OK);
2393 if (Draw_IsConsoleSubsystem) {
2394 hThread = CreateThread (NULL, // no security attributes
2395 0, // use default stack size
2396 readStdinThreadFunc, // thread function
2397 NULL, // no thread function argument
2398 0, // use default creation flags
2399 &IDThread); // returns thread identifier
2401 std::cout << "pb in creation of the thread reading stdin" << std::endl;
2402 Draw_IsConsoleSubsystem = Standard_False;
2403 Init_Appli (GetModuleHandleW (NULL),
2404 GetModuleHandleW (NULL),
2405 1, hWnd); // reinit => create MDI client wnd
2409 //turn on the command interpretation mechanism (regardless of the mode)
2410 if (console_semaphore == STOP_CONSOLE)
2411 console_semaphore = WAIT_CONSOLE_COMMAND;
2413 //simple Win32 message loop
2414 while (GetMessageW (&msg, NULL, 0, 0) > 0)
2416 if (!TranslateAcceleratorW (hWnd, hAccel, &msg))
2418 TranslateMessage (&msg);
2419 DispatchMessageW (&msg);
2426 /*--------------------------------------------------------*\
2428 \*--------------------------------------------------------*/
2429 void Destroy_Appli(HINSTANCE hInst)
2431 UnregisterAppClass(hInst);
2432 for (int i = 0 ; i < MAXCOLOR ; i++)
2433 DeleteObject(colorPenTab[i]);
2436 /*--------------------------------------------------------*\
2438 \*--------------------------------------------------------*/
2439 void DrawWindow::SelectWait(HANDLE& hWnd, int& x, int& y, int& button)
2445 GetMessageW (&msg, NULL, 0, 0);
2446 while((msg.message != WM_RBUTTONDOWN && msg.message != WM_LBUTTONDOWN) ||
2447 ! ( Draw_IsConsoleSubsystem || IsChild(DrawWindow::hWndClientMDI,msg.hwnd)) )
2449 GetMessageW (&msg, NULL, 0, 0);
2453 x = LOWORD(msg.lParam);
2454 y = HIWORD(msg.lParam);
2455 if (msg.message == WM_LBUTTONDOWN)
2461 /*--------------------------------------------------------*\
2463 \*--------------------------------------------------------*/
2464 void DrawWindow::SelectNoWait(HANDLE& hWnd, int& x, int& y, int& button)
2470 GetMessageW (&msg,NULL,0,0);
2471 while((msg.message != WM_RBUTTONDOWN && msg.message != WM_LBUTTONDOWN &&
2472 msg.message != WM_MOUSEMOVE) ||
2473 ! ( Draw_IsConsoleSubsystem || IsChild(DrawWindow::hWndClientMDI,msg.hwnd) ) )
2475 GetMessageW(&msg,NULL,0,0);
2478 x = LOWORD(msg.lParam);
2479 y = HIWORD(msg.lParam);
2480 switch (msg.message)
2482 case WM_LBUTTONDOWN :
2486 case WM_RBUTTONDOWN :
2496 Standard_Boolean DrawWindow::DefineColor (const Standard_Integer, const char*)
2498 return Standard_True;