// Created on: 1994-07-27 // Created by: Remi LEQUETTE // Copyright (c) 1994-1999 Matra Datavision // Copyright (c) 1999-2014 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. // include windows.h first to have all definitions available #ifdef _WIN32 #include #endif #include #include #include #include #include #include #include #include #include extern Standard_Boolean Draw_Batch; extern Standard_Boolean Draw_VirtualWindows; static NCollection_List MyCallbacks; void Draw_Window::AddCallbackBeforeTerminate(FCallbackBeforeTerminate theCB) { MyCallbacks.Append(theCB); } void Draw_Window::RemoveCallbackBeforeTerminate(FCallbackBeforeTerminate theCB) { NCollection_List::Iterator Iter(MyCallbacks); for(; Iter.More(); Iter.Next()) { if (Iter.Value() == theCB) { MyCallbacks.Remove(Iter); break; } } } /* *---------------------------------------------------------------------- * * Prompt -- * * Issue a prompt on standard output, or invoke a script * to issue the prompt. * * Results: * None. * * Side effects: * A prompt gets output, and a Tcl script may be evaluated * in interp. * *---------------------------------------------------------------------- */ static void Prompt(Tcl_Interp *Interp, int partial) { Tcl_Channel errChannel; Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT); const char* promptCmd = Tcl_GetVar (Interp, partial ? "tcl_prompt2" : "tcl_prompt1", TCL_GLOBAL_ONLY); if (promptCmd == NULL) { defaultPrompt: if (!partial && outChannel) { Tcl_Write(outChannel, "% ", 2); } } else { int code = Tcl_Eval(Interp, promptCmd); outChannel = Tcl_GetStdChannel(TCL_STDOUT); errChannel = Tcl_GetStdChannel(TCL_STDERR); if (code != TCL_OK) { if (errChannel) { #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5))) Tcl_Write(errChannel, Tcl_GetStringResult(Interp), -1); #else Tcl_Write(errChannel, Interp->result, -1); #endif Tcl_Write(errChannel, "\n", 1); } Tcl_AddErrorInfo(Interp, "\n (script that generates prompt)"); goto defaultPrompt; } } if (outChannel) { Tcl_Flush(outChannel); } } #if !defined(_WIN32) && !defined(__WIN32__) #include #include #include #if defined(__APPLE__) && !defined(MACOSX_USE_GLX) // use forward declaration for small subset of used Tk functions // to workaround broken standard Tk framework installation within OS X SDKs // which *HAS* X11 headers in Tk.framework but doesn't install them appropriately #define _TK typedef struct Tk_Window_* Tk_Window; typedef const char* Tk_Uid; extern "C" int Tk_Init (Tcl_Interp* interp); extern "C" void Tk_MainLoop(); extern "C" Tk_Window Tk_MainWindow (Tcl_Interp* interp) ; extern "C" Tk_Uid Tk_GetUid (const char* str); extern "C" const char* Tk_SetAppName (Tk_Window tkwin, const char* name) ; extern "C" void Tk_GeometryRequest (Tk_Window tkwin, int reqWidth, int reqHeight); #else #include #endif /* * Global variables used by the main program: */ char *tcl_RcFileName = NULL; /* Name of a user-specific startup script * to source if the application is being run * interactively (e.g. "~/.wishrc"). Set * by Tcl_AppInit. NULL means don't source * anything ever. */ static Tcl_DString command; /* Used to assemble lines of terminal input * into Tcl commands. */ static Tcl_DString line; /* Used to read the next line from the * terminal input. */ //static char errorExitCmd[] = "exit 1"; /* * Forward declarations for procedures defined later in this file: */ static void StdinProc (ClientData clientData, int mask); static void Prompt (Tcl_Interp *Interp, int partial); static Standard_Boolean tty; /* Non-zero means standard input is a * terminal-like device. Zero means it's * a file. */ Standard_Integer Draw_WindowScreen = 0; Standard_Boolean Draw_BlackBackGround = Standard_True; // Initialization of static variables of Draw_Window //====================================================== Draw_Window* Draw_Window::firstWindow = NULL; // X11 specific part #if !defined(__APPLE__) || defined(MACOSX_USE_GLX) #include #include static unsigned long thePixels[MAXCOLOR]; Display* Draw_WindowDisplay = NULL; Colormap Draw_WindowColorMap; static Handle(Aspect_DisplayConnection) Draw_DisplayConnection; // Base_Window struct definition //=================================== struct Base_Window { GC gc; XSetWindowAttributes xswa; }; //======================================================================= //function : Draw_Window //purpose : //======================================================================= Draw_Window::Draw_Window() : base(*new Base_Window()), win(0), myBuffer(0), next(firstWindow), previous(NULL), myUseBuffer(Standard_False), withWindowManager(Standard_True) { myMother = RootWindow(Draw_WindowDisplay, Draw_WindowScreen); if (firstWindow) firstWindow->previous = this; firstWindow = this; } //======================================================================= //function : Draw_Window //purpose : //======================================================================= Draw_Window::Draw_Window(Window mother) : base(*new Base_Window()), win(0), myBuffer(0), next(firstWindow), previous(NULL), myUseBuffer(Standard_False), withWindowManager(Standard_True) { myMother = mother; if (firstWindow) firstWindow->previous = this; firstWindow = this; } //======================================================================= //function : Draw_Window //purpose : //======================================================================= Draw_Window::Draw_Window (const char* title, Standard_Integer X, Standard_Integer Y, Standard_Integer DX, Standard_Integer DY) : base(*new Base_Window()), win(0), myBuffer(0), next(firstWindow), previous(NULL), myUseBuffer(Standard_False), withWindowManager(Standard_True) { myMother = RootWindow(Draw_WindowDisplay, Draw_WindowScreen); if (firstWindow) firstWindow->previous = this; firstWindow = this; Init(X,Y,DX,DY); SetTitle(title); } //======================================================================= //function : Draw_Window //purpose : //======================================================================= Draw_Window::Draw_Window (const char* window ) : base(*new Base_Window()), win(0), myBuffer(0), next(firstWindow), previous(NULL), myUseBuffer(Standard_False), withWindowManager(Standard_True) { sscanf(window,"%lx",&win); Standard_Integer X,Y,DX,DY; if (firstWindow) firstWindow->previous = this; firstWindow = this; GetPosition(X,Y); DX=HeightWin(); DY=WidthWin(); Init(X,Y,DX,DY); } //======================================================================= //function : Draw_Window //purpose : //======================================================================= Draw_Window::Draw_Window (Window mother, char* title, Standard_Integer X, Standard_Integer Y, Standard_Integer DX, Standard_Integer DY) : base(*new Base_Window()), win(0), myBuffer(0), next(firstWindow), previous(NULL), myUseBuffer(Standard_False), withWindowManager(Standard_True) { myMother = mother; if (firstWindow) firstWindow->previous = this; firstWindow = this; Init(X,Y,DX,DY); SetTitle(title); } //======================================================================= //function : ~Draw_Window //purpose : //======================================================================= Draw_Window::~Draw_Window() { if (previous) previous->next = next; else firstWindow = next; if (next) next->previous = previous; if (myBuffer != 0) { XFreePixmap(Draw_WindowDisplay, myBuffer); myBuffer = 0; } // Liberation pointer on Base_Window delete &base; } //======================================================================= //function : Init //purpose : //======================================================================= void Draw_Window::Init(Standard_Integer X, Standard_Integer Y, Standard_Integer DX, Standard_Integer DY) { unsigned long setmask; if (Draw_BlackBackGround) { base.xswa.background_pixel = BlackPixel(Draw_WindowDisplay,Draw_WindowScreen); base.xswa.border_pixel = WhitePixel(Draw_WindowDisplay,Draw_WindowScreen); } else { base.xswa.background_pixel = WhitePixel(Draw_WindowDisplay,Draw_WindowScreen); base.xswa.border_pixel = BlackPixel(Draw_WindowDisplay,Draw_WindowScreen); } base.xswa.colormap = Draw_WindowColorMap; setmask = CWBackPixel | CWBorderPixel ; XSizeHints myHints; myHints.flags = USPosition; myHints.x = (int) X; myHints.y = (int) Y; if (win == 0) { win = XCreateWindow(Draw_WindowDisplay, myMother, (int) X,(int) Y, (unsigned int) DX,(unsigned int) DY, 5, DefaultDepth(Draw_WindowDisplay,Draw_WindowScreen), InputOutput, DefaultVisual(Draw_WindowDisplay,Draw_WindowScreen), setmask,&base.xswa); XSelectInput(Draw_WindowDisplay, win, ButtonPressMask|ExposureMask| StructureNotifyMask); // advise to the window manager to place it where I need XSetWMNormalHints(Draw_WindowDisplay,win,&myHints); Atom aDeleteWindowAtom = Draw_DisplayConnection->GetAtom (Aspect_XA_DELETE_WINDOW); XSetWMProtocols (Draw_WindowDisplay, win, &aDeleteWindowAtom, 1); if (Draw_VirtualWindows) { myUseBuffer = Standard_True; InitBuffer(); } } base.gc = XCreateGC(Draw_WindowDisplay, win, 0, NULL); XSetPlaneMask(Draw_WindowDisplay,base.gc,AllPlanes); XSetForeground(Draw_WindowDisplay, base.gc, WhitePixel(Draw_WindowDisplay,Draw_WindowScreen)); XSetBackground(Draw_WindowDisplay, base.gc, BlackPixel(Draw_WindowDisplay,Draw_WindowScreen)); // save in case of window recovery base.xswa.backing_store = Always; XChangeWindowAttributes(Draw_WindowDisplay, win, CWBackingStore, &base.xswa); XSetLineAttributes (Draw_WindowDisplay, base.gc, 0, LineSolid, CapButt, JoinMiter); } //======================================================================= //function : InitBuffer //purpose : //======================================================================= void Draw_Window::InitBuffer() { if (myUseBuffer) { if (myBuffer != 0) { XFreePixmap (Draw_WindowDisplay, myBuffer); } XWindowAttributes winAttr; XGetWindowAttributes (Draw_WindowDisplay, win, &winAttr); myBuffer = XCreatePixmap (Draw_WindowDisplay, win, winAttr.width, winAttr.height, winAttr.depth); } else if (myBuffer != 0) { XFreePixmap (Draw_WindowDisplay, myBuffer); myBuffer = 0; } } //======================================================================= //function : StopWinManager //purpose : //======================================================================= void Draw_Window::StopWinManager() { // XGCValues winGc; XWindowAttributes winAttr; XGetWindowAttributes (Draw_WindowDisplay, win, &winAttr); Destroy(); XSizeHints myHints; myHints.flags = USPosition; myHints.x = (int) 30; myHints.y = (int) 100; base.xswa.override_redirect = 1; base.xswa.border_pixel = BlackPixel(Draw_WindowDisplay, Draw_WindowScreen); base.xswa.background_pixel = WhitePixel(Draw_WindowDisplay, Draw_WindowScreen); withWindowManager = Standard_False; win = XCreateWindow(Draw_WindowDisplay, myMother, winAttr.x, winAttr.y, winAttr.width, winAttr.height, 2, CopyFromParent, InputOutput, CopyFromParent, CWBorderPixel|CWOverrideRedirect|CWBackPixel, &base.xswa); // adwise to the window manager to place it where I wish XSetWMNormalHints(Draw_WindowDisplay,win,&myHints); // all masks of the old window are reassigned to the new one. XSelectInput(Draw_WindowDisplay,win,winAttr.your_event_mask); } //======================================================================= //function : SetPosition //purpose : //======================================================================= void Draw_Window::SetPosition(Standard_Integer NewXpos, Standard_Integer NewYpos) { Standard_Integer x,y; GetPosition(x, y); if ( (x != NewXpos) || (y != NewYpos) ) XMoveWindow(Draw_WindowDisplay, win, NewXpos, NewYpos); } //======================================================================= //function : SetDimension //purpose : //======================================================================= void Draw_Window::SetDimension(Standard_Integer NewDx, Standard_Integer NewDy) { if ( (NewDx != WidthWin() ) || (NewDy != HeightWin() ) ) XResizeWindow(Draw_WindowDisplay, win, NewDx, NewDy); } //======================================================================= //function : GetPosition //purpose : //======================================================================= void Draw_Window::GetPosition(Standard_Integer &PosX, Standard_Integer &PosY) { XWindowAttributes winAttr; XGetWindowAttributes(Draw_WindowDisplay, win, &winAttr); PosX = winAttr.x; PosY = winAttr.y; } //======================================================================= //function : HeightWin //purpose : //======================================================================= Standard_Integer Draw_Window::HeightWin() const { Standard_Integer DY; XWindowAttributes winAttr; XGetWindowAttributes(Draw_WindowDisplay, win, &winAttr); DY = winAttr.height; return DY; } //======================================================================= //function : WidthWin //purpose : //======================================================================= Standard_Integer Draw_Window::WidthWin() const { Standard_Integer DX; XWindowAttributes winAttr; XGetWindowAttributes(Draw_WindowDisplay, win, &winAttr); DX = winAttr.width; return DX; } //======================================================================= //function : SetTitle //purpose : //======================================================================= void Draw_Window::SetTitle(const TCollection_AsciiString& theTitle) { XStoreName (Draw_WindowDisplay, win, theTitle.ToCString()); } //======================================================================= //function : GetTitle //purpose : //======================================================================= TCollection_AsciiString Draw_Window::GetTitle() const { char* aTitle = NULL; XFetchName (Draw_WindowDisplay, win, &aTitle); return TCollection_AsciiString (aTitle); } //======================================================================= //function : GetDrawable //purpose : //======================================================================= Drawable Draw_Window::GetDrawable() const { return myUseBuffer ? myBuffer : win; } //======================================================================= //function :DefineColor //purpose : //======================================================================= Standard_Boolean Draw_Window::DefineColor(const Standard_Integer i, const char* colorName) { XColor color; if (!XParseColor(Draw_WindowDisplay,Draw_WindowColorMap,colorName,&color)) return Standard_False; if (!XAllocColor(Draw_WindowDisplay,Draw_WindowColorMap,&color)) return Standard_False; thePixels[i % MAXCOLOR] = color.pixel; return Standard_True; } //======================================================================= //function : IsMapped //purpose : //======================================================================= bool Draw_Window::IsMapped() const { if (Draw_VirtualWindows || win == 0) { return false; } XFlush (Draw_WindowDisplay); XWindowAttributes aWinAttr; XGetWindowAttributes (Draw_WindowDisplay, win, &aWinAttr); return aWinAttr.map_state == IsUnviewable || aWinAttr.map_state == IsViewable; } //======================================================================= //function : DisplayWindow //purpose : //======================================================================= void Draw_Window::DisplayWindow() { if (Draw_VirtualWindows) { return; } else { XMapRaised(Draw_WindowDisplay, win); } XFlush(Draw_WindowDisplay); } //======================================================================= //function : Hide //purpose : //======================================================================= void Draw_Window::Hide() { XUnmapWindow(Draw_WindowDisplay, win); } //======================================================================= //function : Destroy //purpose : //======================================================================= void Draw_Window::Destroy() { XFreeGC (Draw_WindowDisplay, base.gc); XDestroyWindow(Draw_WindowDisplay, win); win = 0; if (myBuffer != 0) { XFreePixmap(Draw_WindowDisplay, myBuffer); myBuffer = 0; } } //======================================================================= //function : Clear //purpose : //======================================================================= void Draw_Window::Clear() { if (myUseBuffer) { // XClearArea only applicable for windows XGCValues currValues; XGetGCValues(Draw_WindowDisplay, base.gc, GCBackground | GCForeground, &currValues); XSetForeground(Draw_WindowDisplay, base.gc, currValues.background); XFillRectangle(Draw_WindowDisplay, myBuffer, base.gc, 0, 0, WidthWin(), HeightWin()); XSetForeground(Draw_WindowDisplay, base.gc, currValues.foreground); } else { XClearArea(Draw_WindowDisplay, win, 0, 0, 0, 0, False); } } //======================================================================= //function : Flush //purpose : //======================================================================= void Draw_Window::Flush() { XFlush(Draw_WindowDisplay); } //======================================================================= //function : DrawString //purpose : //======================================================================= void Draw_Window::DrawString(int X, int Y, char *text) { XDrawString(Draw_WindowDisplay, GetDrawable(), base.gc, X, Y, text, strlen(text)); } //======================================================================= //function : DrawSegments //purpose : //======================================================================= void Draw_Window::DrawSegments(Segment *tab, int nbElem) { XDrawSegments(Draw_WindowDisplay, GetDrawable(), base.gc, (XSegment*) tab, nbElem); } //======================================================================= //function : Redraw //purpose : //======================================================================= void Draw_Window::Redraw() { if (myUseBuffer) { XCopyArea (Draw_WindowDisplay, myBuffer, win, // source, destination Drawables base.gc, 0, 0, // source x, y WidthWin(), HeightWin(), 0, 0); // destination x, y } } //======================================================================= //function : SetColor //purpose : //======================================================================= void Draw_Window::SetColor(Standard_Integer color) { XSetForeground(Draw_WindowDisplay, base.gc, thePixels[color]); } //======================================================================= //function : SetMode //purpose : //======================================================================= void Draw_Window::SetMode( int mode) { XSetFunction(Draw_WindowDisplay, base.gc, mode); } //======================================================================= //function : Save //purpose : //======================================================================= Standard_Boolean Draw_Window::Save (const char* theFileName) const { // make sure all draw operations done XSync (Draw_WindowDisplay, True); // the attributes XWindowAttributes winAttr; XGetWindowAttributes (Draw_WindowDisplay, win, &winAttr); if (!myUseBuffer) { // make sure that the whole window fit on display to prevent BadMatch error XWindowAttributes winAttrRoot; XGetWindowAttributes (Draw_WindowDisplay, XRootWindowOfScreen (winAttr.screen), &winAttrRoot); Window winChildDummy; int winLeft = 0; int winTop = 0; XTranslateCoordinates (Draw_WindowDisplay, win, XRootWindowOfScreen (winAttr.screen), 0, 0, &winLeft, &winTop, &winChildDummy); if (((winLeft + winAttr.width) > winAttrRoot.width) || winLeft < winAttrRoot.x || ((winTop + winAttr.height) > winAttrRoot.height) || winTop < winAttrRoot.y) { std::cerr << "The window not fully visible! Can't create the snapshot.\n"; return Standard_False; } } XVisualInfo aVInfo; if (XMatchVisualInfo (Draw_WindowDisplay, Draw_WindowScreen, 32, TrueColor, &aVInfo) == 0 && XMatchVisualInfo (Draw_WindowDisplay, Draw_WindowScreen, 24, TrueColor, &aVInfo) == 0) { std::cerr << "24-bit TrueColor visual is not supported by server!\n"; return Standard_False; } Image_AlienPixMap anImage; bool isBigEndian = Image_PixMap::IsBigEndianHost(); const Standard_Size aSizeRowBytes = Standard_Size(winAttr.width) * 4; if (!anImage.InitTrash (isBigEndian ? Image_Format_RGB32 : Image_Format_BGR32, Standard_Size(winAttr.width), Standard_Size(winAttr.height), aSizeRowBytes)) { return Standard_False; } anImage.SetTopDown (true); XImage* anXImage = XCreateImage (Draw_WindowDisplay, aVInfo.visual, 32, ZPixmap, 0, (char* )anImage.ChangeData(), winAttr.width, winAttr.height, 32, int(aSizeRowBytes)); anXImage->bitmap_bit_order = anXImage->byte_order = (isBigEndian ? MSBFirst : LSBFirst); if (XGetSubImage (Draw_WindowDisplay, GetDrawable(), 0, 0, winAttr.width, winAttr.height, AllPlanes, ZPixmap, anXImage, 0, 0) == NULL) { anXImage->data = NULL; XDestroyImage (anXImage); return Standard_False; } // destroy the image anXImage->data = NULL; XDestroyImage (anXImage); // save the image return anImage.Save (theFileName); } //======================================================================= //function : Wait //purpose : //======================================================================= void Draw_Window::Wait (Standard_Boolean wait) { Flush(); if (!wait) { XSelectInput(Draw_WindowDisplay,win, ButtonPressMask|ExposureMask | StructureNotifyMask | PointerMotionMask); } else { XSelectInput(Draw_WindowDisplay,win, ButtonPressMask|ExposureMask | StructureNotifyMask); } } //======================================================================= //function : ProcessEvent //purpose : //======================================================================= void ProcessEvent(Draw_Window& win, XEvent& xev) { Standard_Integer X,Y,button; KeySym keysym; XComposeStatus stat; char chainekey[10]; switch (xev.type) { case ClientMessage: { if (xev.xclient.data.l[0] == (int )Draw_DisplayConnection->GetAtom (Aspect_XA_DELETE_WINDOW)) { // just hide the window win.Hide(); } return; } case Expose : win.WExpose(); break; case ButtonPress : X = xev.xbutton.x; Y = xev.xbutton.y; button = xev.xbutton.button; win.WButtonPress(X,Y,button); break; case ButtonRelease : X = xev.xbutton.x; Y = xev.xbutton.y; button = xev.xbutton.button; win.WButtonRelease(X,Y,button); break; case KeyPress : XLookupString(&(xev.xkey), chainekey, 10, &keysym, &stat); break; case MotionNotify : X = xev.xmotion.x; Y = xev.xmotion.y; win.WMotionNotify(X,Y); break; case ConfigureNotify : if (win.withWindowManager) win.WConfigureNotify(xev.xconfigure.x, xev.xconfigure.y, xev.xconfigure.width, xev.xconfigure.height); break; case UnmapNotify : win.WUnmapNotify(); break; } } //======================================================================= //function : WExpose //purpose : //======================================================================= void Draw_Window::WExpose() { } //======================================================================= //function : WButtonPress //purpose : //======================================================================= void Draw_Window::WButtonPress(const Standard_Integer, const Standard_Integer, const Standard_Integer&) { } //======================================================================= //function : WButtonRelease //purpose : //======================================================================= void Draw_Window::WButtonRelease(const Standard_Integer, const Standard_Integer, const Standard_Integer&) { } /************************** //======================================================================= //function : WKeyPress //purpose : //======================================================================= void Draw_Window::WKeyPress(char, KeySym&) { } ***************************/ //======================================================================= //function : WMotionNotify //purpose : //======================================================================= void Draw_Window::WMotionNotify(const Standard_Integer , const Standard_Integer ) { } //======================================================================= //function : WConfigureNotify //purpose : //======================================================================= void Draw_Window::WConfigureNotify(const Standard_Integer, const Standard_Integer, const Standard_Integer, const Standard_Integer) { } //======================================================================= //function : WUnmapNotify //purpose : //======================================================================= void Draw_Window::WUnmapNotify() { } //====================================================== // function : ProcessEvents // purpose : process pending X events //====================================================== static void ProcessEvents(ClientData,int) { // test for X Event while (XPending(Draw_WindowDisplay)) { XEvent xev; xev.type = 0; XNextEvent(Draw_WindowDisplay,&xev); /* search the window in the window list */ Draw_Window* w = Draw_Window::firstWindow; Standard_Integer found=0; while (w) { if (xev.xany.window == w->win) { ProcessEvent(*w, xev); found=1; break; } w = w->next; } if (found==0) { Tk_HandleEvent(&xev); } } } //====================================================== // function : GetNextEvent() // purpose : //====================================================== void GetNextEvent(Event& ev) { XEvent xev; XNextEvent(Draw_WindowDisplay, &xev); switch(xev.type) { case ButtonPress : ev.type = 4; ev.window = xev.xbutton.window; ev.button = xev.xbutton.button; ev.x = xev.xbutton.x; ev.y = xev.xbutton.y; break; case MotionNotify : ev.type = 6; ev.window = xev.xmotion.window; ev.button = 0; ev.x = xev.xmotion.x; ev.y = xev.xmotion.y; break; } } #endif //__APPLE__ //====================================================== // function :Run_Appli // purpose : //====================================================== static Standard_Boolean(*Interprete) (const char*); void Run_Appli(Standard_Boolean (*interprete) (const char*)) { Tcl_Channel outChannel, inChannel ; Interprete = interprete; #ifdef _TK /* * Commands will come from standard input, so set up an event * handler for standard input. If the input device is aEvaluate the * .rc file, if one has been specified, set up an event handler * for standard input, and print a prompt if the input * device is a terminal. */ inChannel = Tcl_GetStdChannel(TCL_STDIN); if (inChannel) { Tcl_CreateChannelHandler(inChannel, TCL_READABLE, StdinProc, (ClientData) inChannel); } // Create a handler for the draw display // Adding of the casting into void* to be able to compile on AO1 // ConnectionNumber(Draw_WindowDisplay) is an int 32 bits // (void*) is a pointer 64 bits ??????? #if !defined(__APPLE__) || defined(MACOSX_USE_GLX) #if TCL_MAJOR_VERSION < 8 Tk_CreateFileHandler((void*) ConnectionNumber(Draw_WindowDisplay), TK_READABLE, ProcessEvents,(ClientData) 0 ); #else Tk_CreateFileHandler(ConnectionNumber(Draw_WindowDisplay), TK_READABLE, ProcessEvents,(ClientData) 0 ); #endif #endif // __APPLE__ #endif Draw_Interpretor& aCommands = Draw::GetInterpretor(); if (tty) Prompt(aCommands.Interp(), 0); Prompt(aCommands.Interp(), 0); outChannel = Tcl_GetStdChannel(TCL_STDOUT); if (outChannel) { Tcl_Flush(outChannel); } Tcl_DStringInit(&command); /* * Loop infinitely, waiting for commands to execute. When there * are no windows left, Tk_MainLoop returns and we exit. */ #ifdef _TK if (Draw_VirtualWindows) { // main window will never shown // but main loop will parse all Xlib messages Tcl_Eval(aCommands.Interp(), "wm withdraw ."); } Tk_MainLoop(); #else fd_set readset; Standard_Integer count = ConnectionNumber(Draw_WindowDisplay); Standard_Integer numfd; while (1) { FD_ZERO(&readset); FD_SET(0,&readset); FD_SET(count,&readset); #ifdef HPUX numfd = select(count+1,(Integer*)&readset,NULL,NULL,NULL); #else numfd = select(count+1,&readset,NULL,NULL,NULL); #endif if (FD_ISSET(0,&readset)) StdinProc((ClientData)0,0); if (FD_ISSET(count,&readset)) ProcessEvents((ClientData)0,0); } #endif NCollection_List::Iterator Iter(MyCallbacks); for(; Iter.More(); Iter.Next()) { (*Iter.Value())(); } } //====================================================== // function : Init_Appli() // purpose : //====================================================== Standard_Boolean Init_Appli() { Draw_Interpretor& aCommands = Draw::GetInterpretor(); aCommands.Init(); Tcl_Interp *interp = aCommands.Interp(); Tcl_Init (interp); try { OCC_CATCH_SIGNALS Tk_Init(interp) ; } catch (Standard_Failure const&) { std::cout <<" Pb au lancement de TK_Init "< 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5))) fprintf(stderr, "%s\n", Tcl_GetStringResult(interp)); #else fprintf(stderr, "%s\n", interp->result); #endif exit(1); } #if defined(__APPLE__) && !defined(MACOSX_USE_GLX) Tk_SetAppName(aMainWindow, "Draw"); #else Tk_Name(aMainWindow) = Tk_GetUid(Tk_SetAppName(aMainWindow, "Draw")); #endif Tk_GeometryRequest (aMainWindow, 200, 200); #if !defined(__APPLE__) || defined(MACOSX_USE_GLX) if (Draw_DisplayConnection.IsNull()) { try { Draw_DisplayConnection = new Aspect_DisplayConnection(); } catch (Standard_Failure const&) { std::cout << "Cannot open display. Interpret commands in batch mode." << std::endl; return Standard_False; } } if (Draw_WindowDisplay == NULL) { Draw_WindowDisplay = Draw_DisplayConnection->GetDisplay(); } // // synchronize the display server : could be done within Tk_Init // XSynchronize(Draw_WindowDisplay, True); XSetInputFocus(Draw_WindowDisplay, PointerRoot, RevertToPointerRoot, CurrentTime); Draw_WindowScreen = DefaultScreen(Draw_WindowDisplay); Draw_WindowColorMap = DefaultColormap(Draw_WindowDisplay, Draw_WindowScreen); #endif // __APPLE__ tty = isatty(0); Tcl_SetVar(interp,"tcl_interactive",(char*)(tty ? "1" : "0"), TCL_GLOBAL_ONLY); // Tcl_SetVar(interp,"tcl_interactive",tty ? "1" : "0", TCL_GLOBAL_ONLY); return Standard_True; } //====================================================== // function : Destroy_Appli() // purpose : //====================================================== void Destroy_Appli() { //XCloseDisplay(Draw_WindowDisplay); } /* *---------------------------------------------------------------------- * * StdinProc -- * * This procedure is invoked by the event dispatcher whenever * standard input becomes readable. It grabs the next line of * input characters, adds them to a command being assembled, and * executes the command if it's complete. * * Results: * None. * * Side effects: * Could be almost arbitrary, depending on the command that's * typed. * *---------------------------------------------------------------------- */ /* ARGSUSED */ //static void StdinProc(ClientData clientData, int mask) static void StdinProc(ClientData clientData, int ) { static int gotPartial = 0; char *cmd; // int code, count; int count; Tcl_Channel chan = (Tcl_Channel) clientData; // MSV Nov 2, 2001: patch for TCL 8.3: initialize line to avoid exception // when first user input is an empty string Tcl_DStringFree(&line); count = Tcl_Gets(chan, &line); // MKV 26.05.05 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) Tcl_DString linetmp; Tcl_DStringInit(&linetmp); Tcl_UniChar * UniCharString; UniCharString = Tcl_UtfToUniCharDString(Tcl_DStringValue(&line),-1,&linetmp); Standard_Integer l = Tcl_UniCharLen(UniCharString); TCollection_AsciiString AsciiString(""); Standard_Character Character; Standard_Integer i; for (i=0; i #include #include #define PENWIDTH 1 #define CLIENTWND 0 // Position of information in the extra memory // indicates SUBSYSTEM:CONSOLE linker option, to be set to True in main() Standard_EXPORT Standard_Boolean Draw_IsConsoleSubsystem = Standard_False; Standard_Boolean Draw_BlackBackGround = Standard_True; // Creation of color stylos HPEN colorPenTab[MAXCOLOR] = {CreatePen(PS_SOLID, PENWIDTH, RGB(255,255,255)), CreatePen(PS_SOLID, PENWIDTH, RGB(255,0,0)), CreatePen(PS_SOLID, PENWIDTH, RGB(0,255,0)), CreatePen(PS_SOLID, PENWIDTH, RGB(0,0,255)), CreatePen(PS_SOLID, PENWIDTH, RGB(0,255,255)), CreatePen(PS_SOLID, PENWIDTH, RGB(255,215,0)), CreatePen(PS_SOLID, PENWIDTH, RGB(255,0,255)), CreatePen(PS_SOLID, PENWIDTH, RGB(255,52,179)), CreatePen(PS_SOLID, PENWIDTH, RGB(255,165,0)), CreatePen(PS_SOLID, PENWIDTH, RGB(255,228,225)), CreatePen(PS_SOLID, PENWIDTH, RGB(255,160,122)), CreatePen(PS_SOLID, PENWIDTH, RGB(199,21,133)), CreatePen(PS_SOLID, PENWIDTH, RGB(255,255,0)), CreatePen(PS_SOLID, PENWIDTH, RGB(240,230,140)), CreatePen(PS_SOLID, PENWIDTH, RGB(255,127,80))}; // Correspondence mode X11 and WINDOWS NT int modeTab[16] = {R2_BLACK, R2_MASKPEN, R2_MASKPENNOT, R2_COPYPEN, R2_MASKNOTPEN, R2_NOP, R2_XORPEN, R2_MERGEPEN, R2_NOTMASKPEN, R2_NOTXORPEN, R2_NOT, R2_MERGEPENNOT, R2_NOTCOPYPEN, R2_MERGENOTPEN, R2_NOTMERGEPEN, R2_WHITE}; /*--------------------------------------------------------*\ | CREATE DRAW WINDOW PROCEDURE \*--------------------------------------------------------*/ HWND DrawWindow::CreateDrawWindow(HWND hWndClient, int nitem) { if (Draw_IsConsoleSubsystem) { HWND aWin = CreateWindowW (DRAWCLASS, DRAWTITLE, WS_OVERLAPPEDWINDOW, 1,1,1,1, NULL, NULL,::GetModuleHandle(NULL), NULL); if (!Draw_VirtualWindows) { SetWindowPos(aWin, HWND_TOPMOST, 1,1,1,1, SWP_NOMOVE); SetWindowPos(aWin, HWND_NOTOPMOST, 1,1,1,1, SWP_NOMOVE); } return aWin; } else { HANDLE hInstance = (HANDLE )GetWindowLongPtrW (hWndClient, GWLP_HINSTANCE); return CreateMDIWindowW(DRAWCLASS, DRAWTITLE, WS_CAPTION | WS_CHILD | WS_THICKFRAME, 1,1,0,0, hWndClient, (HINSTANCE)hInstance, nitem); } } /*--------------------------------------------------------*\ | DRAW WINDOW PROCEDURE \*--------------------------------------------------------*/ LRESULT APIENTRY DrawWindow::DrawProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam ) { DrawWindow* localObjet = (DrawWindow* )GetWindowLongPtrW (hWnd, CLIENTWND); if (!localObjet) { return Draw_IsConsoleSubsystem ? DefWindowProcW (hWnd, wMsg, wParam, lParam) : DefMDIChildProcW (hWnd, wMsg, wParam, lParam); } switch (wMsg) { case WM_CLOSE: { localObjet->Hide(); return 0; // do nothing - window destruction should be performed by application } case WM_PAINT: { PAINTSTRUCT ps; BeginPaint (hWnd, &ps); if (localObjet->GetUseBuffer()) { localObjet->Redraw(); } else { localObjet->WExpose(); } EndPaint (hWnd, &ps); return 0; } case WM_SIZE: { if (localObjet->GetUseBuffer()) { localObjet->InitBuffer(); localObjet->WExpose(); localObjet->Redraw(); return 0; } break; } } return Draw_IsConsoleSubsystem ? DefWindowProcW (hWnd, wMsg, wParam, lParam) : DefMDIChildProcW (hWnd, wMsg, wParam, lParam); } /* ** IMPLEMENTATION of the CLASS DRAWWINDOW */ /*--------------------------------------------------------*\ | Initialization of static variables of DrawWindow \*--------------------------------------------------------*/ DrawWindow* DrawWindow::firstWindow = NULL; HWND DrawWindow::hWndClientMDI = 0; /*--------------------------------------------------------*\ | Constructors of Draw_Window \*--------------------------------------------------------*/ // Default Constructor //________________________ DrawWindow::DrawWindow() : win(0), next(firstWindow), previous(NULL), myMemHbm(NULL), myUseBuffer(Standard_False), myCurrPen(0), myCurrMode(0) { if (firstWindow) firstWindow->previous = this; firstWindow = this; } //________________________ DrawWindow::DrawWindow(const char* title, Standard_Integer X, Standard_Integer Y, Standard_Integer dX,Standard_Integer dY) : win(0), next(firstWindow), previous(NULL), myMemHbm(NULL), myUseBuffer(Standard_False) { if (firstWindow) firstWindow->previous = this; firstWindow = this; Init(X, Y, dX, dY); SetTitle(title); } DrawWindow::DrawWindow(const char* title, Standard_Integer X, Standard_Integer Y, Standard_Integer dX,Standard_Integer dY, HWND theWin) : win(theWin),next(firstWindow), previous(NULL), myMemHbm(NULL), myUseBuffer(Standard_False) { if (firstWindow) firstWindow->previous = this; firstWindow = this; Init(X, Y, dX, dY); SetTitle(title); } /*--------------------------------------------------------*\ | Destructor of DrawWindow \*--------------------------------------------------------*/ DrawWindow::~DrawWindow() { if (previous) previous->next = next; else firstWindow = next; if (next) next->previous = previous; // Delete 'off-screen drawing'-related objects if (myMemHbm) { DeleteObject(myMemHbm); myMemHbm = NULL; } } /*--------------------------------------------------------*\ | Init \*--------------------------------------------------------*/ void DrawWindow::Init(Standard_Integer theXLeft, Standard_Integer theYTop, Standard_Integer theWidth, Standard_Integer theHeight) { if (win == NULL) { win = CreateDrawWindow(hWndClientMDI, 0); } // include decorations in the window dimensions // to reproduce same behaviour of Xlib window. DWORD aWinStyle = GetWindowLongW (win, GWL_STYLE); DWORD aWinStyleEx = GetWindowLongW (win, GWL_EXSTYLE); HMENU aMenu = GetMenu (win); RECT aRect; aRect.top = theYTop; aRect.bottom = theYTop + theHeight; aRect.left = theXLeft; aRect.right = theXLeft + theWidth; AdjustWindowRectEx (&aRect, aWinStyle, aMenu != NULL ? TRUE : FALSE, aWinStyleEx); SetPosition (aRect.left, aRect.top); SetDimension (aRect.right - aRect.left, aRect.bottom - aRect.top); // Save the pointer at the instance associated to the window SetWindowLongPtrW (win, CLIENTWND, (LONG_PTR)this); HDC hDC = GetDC(win); SetBkColor(hDC, RGB(0, 0, 0)); myCurrPen = 3; myCurrMode = 3; SelectObject(hDC, colorPenTab[myCurrPen]); // Default pencil SelectObject(hDC, GetStockObject(BLACK_BRUSH)); SetTextColor(hDC, RGB(0,0,255)); ReleaseDC(win, hDC); if (Draw_VirtualWindows) { // create a virtual window SetUseBuffer (Standard_True); } } /*--------------------------------------------------------*\ | SetUseBuffer \*--------------------------------------------------------*/ void DrawWindow::SetUseBuffer(Standard_Boolean use) { myUseBuffer = use; InitBuffer(); } /*--------------------------------------------------------*\ | InitBuffer \*--------------------------------------------------------*/ void DrawWindow::InitBuffer() { if (myUseBuffer) { RECT rc; HDC hDC = GetDC(win); GetClientRect(win, &rc); if (myMemHbm) { BITMAP aBmp; GetObjectW (myMemHbm, sizeof(BITMAP), &aBmp); if (rc.right-rc.left == aBmp.bmWidth && rc.bottom-rc.top == aBmp.bmHeight) return; DeleteObject(myMemHbm); } myMemHbm = (HBITMAP)CreateCompatibleBitmap(hDC, rc.right-rc.left, rc.bottom-rc.top); HDC aMemDC = GetMemDC(hDC); FillRect(aMemDC, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); ReleaseMemDC(aMemDC); ReleaseDC(win, hDC); } else { if (myMemHbm) { DeleteObject(myMemHbm); myMemHbm = NULL; } } } /*--------------------------------------------------------*\ | GetMemDC \*--------------------------------------------------------*/ HDC DrawWindow::GetMemDC(HDC theWinDC) { if (!myUseBuffer) return NULL; HDC aWorkDC = CreateCompatibleDC(theWinDC); myOldHbm = (HBITMAP)SelectObject(aWorkDC, myMemHbm); SetROP2(aWorkDC, modeTab[myCurrMode]); SelectObject(aWorkDC, colorPenTab[myCurrPen]); SetBkColor(aWorkDC, RGB(0, 0, 0)); SelectObject(aWorkDC, GetStockObject(BLACK_BRUSH)); SetTextColor(aWorkDC, RGB(0,0,255)); return aWorkDC; } /*--------------------------------------------------------*\ | ReleaseMemDC \*--------------------------------------------------------*/ void DrawWindow::ReleaseMemDC(HDC theMemDC) { if (!myUseBuffer || !theMemDC) return; if (myOldHbm) SelectObject(theMemDC, myOldHbm); DeleteDC(theMemDC); } /*--------------------------------------------------------*\ | SetPosition \*--------------------------------------------------------*/ void DrawWindow::SetPosition(Standard_Integer posX, Standard_Integer posY) { UINT aFlags = SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER; if (Draw_VirtualWindows) { aFlags |= SWP_NOSENDCHANGING; } SetWindowPos (win, 0, posX, posY, 0, 0, aFlags); } /*--------------------------------------------------------*\ | SetDimension \*--------------------------------------------------------*/ void DrawWindow::SetDimension(Standard_Integer dimX, Standard_Integer dimY) { UINT aFlags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER; if (Draw_VirtualWindows) { aFlags |= SWP_NOSENDCHANGING; } SetWindowPos (win, 0, 0, 0, dimX, dimY, aFlags); } /*--------------------------------------------------------*\ | GetPosition \*--------------------------------------------------------*/ void DrawWindow::GetPosition(Standard_Integer &dimX, Standard_Integer &dimY) { RECT rect; GetWindowRect(win, &rect); POINT point; point.x = rect.left; point.y = rect.top; ScreenToClient(hWndClientMDI, &point); dimX = point.x; dimY = point.y; } /*--------------------------------------------------------*\ | HeightWin \*--------------------------------------------------------*/ Standard_Integer DrawWindow::HeightWin() const { RECT rect; GetClientRect(win, &rect); return(rect.bottom-rect.top); } /*--------------------------------------------------------*\ | WidthWin \*--------------------------------------------------------*/ Standard_Integer DrawWindow::WidthWin() const { RECT rect; GetClientRect(win, &rect); return(rect.right-rect.left); } /*--------------------------------------------------------*\ | SetTitle \*--------------------------------------------------------*/ void DrawWindow::SetTitle (const TCollection_AsciiString& theTitle) { const TCollection_ExtendedString aTitleW (theTitle); SetWindowTextW (win, aTitleW.ToWideString()); } /*--------------------------------------------------------*\ | GetTitle \*--------------------------------------------------------*/ TCollection_AsciiString DrawWindow::GetTitle() const { wchar_t aTitleW[32]; GetWindowTextW (win, aTitleW, 30); return TCollection_AsciiString (aTitleW); } //======================================================================= //function : IsMapped //purpose : //======================================================================= bool Draw_Window::IsMapped() const { if (Draw_VirtualWindows || win == NULL) { return false; } LONG aWinStyle = GetWindowLongW (win, GWL_STYLE); return (aWinStyle & WS_VISIBLE) != 0 && (aWinStyle & WS_MINIMIZE) == 0; } /*--------------------------------------------------------*\ | DisplayWindow \*--------------------------------------------------------*/ void DrawWindow::DisplayWindow() { if (Draw_VirtualWindows) { return; } ShowWindow (win, SW_SHOW); UpdateWindow (win); } /*--------------------------------------------------------*\ | Hide \*--------------------------------------------------------*/ void DrawWindow::Hide() { ShowWindow(win, SW_HIDE); } /*--------------------------------------------------------*\ | Destroy \*--------------------------------------------------------*/ void DrawWindow::Destroy() { DestroyWindow(win); } /*--------------------------------------------------------*\ | Clear \*--------------------------------------------------------*/ void DrawWindow::Clear() { HDC hDC = GetDC(win); HDC aWorkDC = myUseBuffer ? GetMemDC(hDC) : hDC; SaveDC(aWorkDC); SelectObject(aWorkDC,GetStockObject(BLACK_PEN)); Rectangle(aWorkDC, 0, 0, WidthWin(), HeightWin()); RestoreDC(aWorkDC,-1); if (myUseBuffer) ReleaseMemDC(aWorkDC); ReleaseDC(win,hDC); } /*--------------------------------------------------------*\ | SaveBitmap \*--------------------------------------------------------*/ static Standard_Boolean SaveBitmap (HBITMAP theHBitmap, const char* theFileName) { // Get information about the bitmap BITMAP aBitmap; if (GetObjectW (theHBitmap, sizeof(BITMAP), &aBitmap) == 0) { return Standard_False; } Image_AlienPixMap anImage; const Standard_Size aSizeRowBytes = ((Standard_Size(aBitmap.bmWidth) * 24 + 31) / 32) * 4; // 4 bytes alignment for GetDIBits() if (!anImage.InitTrash (Image_Format_BGR, Standard_Size(aBitmap.bmWidth), Standard_Size(aBitmap.bmHeight), aSizeRowBytes)) { return Standard_False; } anImage.SetTopDown (false); // Setup image data BITMAPINFOHEADER aBitmapInfo; memset (&aBitmapInfo, 0, sizeof(BITMAPINFOHEADER)); aBitmapInfo.biSize = sizeof(BITMAPINFOHEADER); aBitmapInfo.biWidth = aBitmap.bmWidth; aBitmapInfo.biHeight = aBitmap.bmHeight; // positive means bottom-up! aBitmapInfo.biPlanes = 1; aBitmapInfo.biBitCount = 24; aBitmapInfo.biCompression = BI_RGB; // Copy the pixels HDC aDC = GetDC (NULL); Standard_Boolean isSuccess = GetDIBits (aDC, theHBitmap, 0, // first scan line to set aBitmap.bmHeight, // number of scan lines to copy anImage.ChangeData(), // array for bitmap bits (LPBITMAPINFO )&aBitmapInfo, // bitmap data info DIB_RGB_COLORS) != 0; ReleaseDC (NULL, aDC); return isSuccess && anImage.Save (theFileName); } /*--------------------------------------------------------*\ | Save \*--------------------------------------------------------*/ Standard_Boolean DrawWindow::Save (const char* theFileName) const { if (myUseBuffer) { return SaveBitmap (myMemHbm, theFileName); } RECT aRect; GetClientRect (win, &aRect); int aWidth = aRect.right - aRect.left; int aHeight = aRect.bottom - aRect.top; // Prepare the DCs HDC aDstDC = GetDC (NULL); HDC aSrcDC = GetDC (win); // we copy only client area HDC aMemDC = CreateCompatibleDC (aDstDC); // Copy the screen to the bitmap HBITMAP anHBitmapDump = CreateCompatibleBitmap (aDstDC, aWidth, aHeight); HBITMAP anHBitmapOld = (HBITMAP )SelectObject (aMemDC, anHBitmapDump); BitBlt (aMemDC, 0, 0, aWidth, aHeight, aSrcDC, 0, 0, SRCCOPY); Standard_Boolean isSuccess = SaveBitmap (anHBitmapDump, theFileName); // Free objects DeleteObject (SelectObject (aMemDC, anHBitmapOld)); DeleteDC (aMemDC); return isSuccess; } /*--------------------------------------------------------*\ | DrawString \*--------------------------------------------------------*/ void DrawWindow::DrawString(int x,int y, char* text) { HDC hDC = GetDC(win); HDC aWorkDC = myUseBuffer ? GetMemDC(hDC) : hDC; TCollection_ExtendedString textW (text); TextOutW(aWorkDC, x, y, (const wchar_t*)textW.ToExtString(), (int )strlen(text)); if (myUseBuffer) ReleaseMemDC(aWorkDC); ReleaseDC(win,hDC); } /*--------------------------------------------------------*\ | DrawSegments \*--------------------------------------------------------*/ void DrawWindow::DrawSegments(Segment *tab, int nbElem) { HDC hDC = GetDC(win); HDC aWorkDC = myUseBuffer ? GetMemDC(hDC) : hDC; for(int i = 0 ; i < nbElem ; i++) { MoveToEx(aWorkDC, tab[i].x1, tab[i].y1, NULL); LineTo(aWorkDC, tab[i].x2, tab[i].y2); } if (myUseBuffer) ReleaseMemDC(aWorkDC); ReleaseDC(win,hDC); } /*--------------------------------------------------------*\ | Redraw \*--------------------------------------------------------*/ void DrawWindow::Redraw() { if (myUseBuffer) { HDC hDC = GetDC(win); RECT rc; GetClientRect(win, &rc); HDC aMemDC = GetMemDC(hDC); BitBlt(hDC, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, aMemDC, 0, 0, SRCCOPY); ReleaseMemDC(aMemDC); ReleaseDC(win,hDC); } } /*--------------------------------------------------------*\ | SetMode \*--------------------------------------------------------*/ void DrawWindow::SetMode(int mode) { HDC hDC = GetDC(win); myCurrMode = mode; SetROP2(hDC, modeTab[mode]); ReleaseDC(win,hDC); } /*--------------------------------------------------------*\ | SetColor \*--------------------------------------------------------*/ void DrawWindow::SetColor(Standard_Integer color) { HDC hDC = GetDC(win); myCurrPen = color; SelectObject(hDC,colorPenTab[color]); ReleaseDC(win,hDC); } /*--------------------------------------------------------*\ | WExpose \*--------------------------------------------------------*/ void DrawWindow::WExpose() { } /*--------------------------------------------------------*\ | WButtonPress \*--------------------------------------------------------*/ void DrawWindow::WButtonPress(const Standard_Integer, const Standard_Integer, const Standard_Integer&) { } /*--------------------------------------------------------*\ | WButtonRelease \*--------------------------------------------------------*/ void DrawWindow::WButtonRelease(const Standard_Integer, const Standard_Integer, const Standard_Integer&) { } /*--------------------------------------------------------*\ | WMotionNotify \*--------------------------------------------------------*/ void Draw_Window::WMotionNotify(const Standard_Integer , const Standard_Integer ) { } /*--------------------------------------------------------*\ | WConfigureNotify \*--------------------------------------------------------*/ void DrawWindow::WConfigureNotify(const Standard_Integer, const Standard_Integer, const Standard_Integer, const Standard_Integer) { } /*--------------------------------------------------------*\ | WUnmapNotify \*--------------------------------------------------------*/ void DrawWindow::WUnmapNotify() { } /* ** IMPLEMENTATION of the CLASS SEGMENT */ /*--------------------------------------------------------*\ | Init \*--------------------------------------------------------*/ void Segment::Init(Standard_Integer a1, Standard_Integer a2, Standard_Integer a3, Standard_Integer a4) { x1=a1; y1=a2; x2=a3; y2=a4; } static DWORD WINAPI tkLoop (LPVOID theThreadParameter); #ifdef _TK static Tk_Window mainWindow; #endif //* threads sinchronization *// DWORD dwMainThreadId; console_semaphore_value volatile console_semaphore = WAIT_CONSOLE_COMMAND; wchar_t console_command[DRAW_COMMAND_SIZE + 1]; bool volatile isTkLoopStarted = false; /*--------------------------------------------------------*\ | Init_Appli \*--------------------------------------------------------*/ Standard_Boolean Init_Appli(HINSTANCE hInst, HINSTANCE hPrevInst, int nShow, HWND& hWndFrame ) { DWORD IDThread; HANDLE hThread; console_semaphore = STOP_CONSOLE; dwMainThreadId = GetCurrentThreadId(); //necessary for normal Tk operation hThread = CreateThread (NULL, // no security attributes 0, // use default stack size tkLoop, // thread function NULL, // no thread function argument 0, // use default creation flags &IDThread); if (!hThread) { std::cout << "Failed to create Tcl/Tk main loop thread. Switching to batch mode..." << std::endl; Draw_Batch = Standard_True; Draw_Interpretor& aCommands = Draw::GetInterpretor(); aCommands.Init(); Tcl_Interp *interp = aCommands.Interp(); Tcl_Init(interp); #ifdef _TK try { OCC_CATCH_SIGNALS Tk_Init(interp); } catch (Standard_Failure& anExcept) { std::cout << "Failed to initialize Tk: " << anExcept.GetMessageString() << std::endl; } Tcl_StaticPackage(interp, "Tk", Tk_Init, (Tcl_PackageInitProc *) NULL); #endif //since the main Tcl/Tk loop wasn't created --> switch to batch mode return Standard_False; } // san - 06/08/2002 - Time for tkLoop to start; Tk fails to initialize otherwise while (!isTkLoopStarted) Sleep(10); // Saving of window classes if(!hPrevInst) if(!RegisterAppClass(hInst)) return(Standard_False); /* ** Enter the application message-polling loop. This is the anchor for ** the application. */ hWndFrame = !Draw_IsConsoleSubsystem ? CreateAppWindow (hInst) : NULL; if (hWndFrame != NULL) { ShowWindow(hWndFrame,nShow); UpdateWindow(hWndFrame); } return Standard_True; } Standard_Boolean Draw_Interprete (const char*); /*--------------------------------------------------------*\ | readStdinThreadFunc \*--------------------------------------------------------*/ static DWORD WINAPI readStdinThreadFunc (const LPVOID theThreadParameter) { (void)theThreadParameter; if (!Draw_IsConsoleSubsystem) { return 1; } // Console locale could be set to the system codepage .OCP (UTF-8 is not properly supported on Windows). // However, to use it, we have to care using std::wcerr/fwprintf/WriteConsoleW for non-ascii strings everywhere (including Tcl itself), // or otherwise we can have incomplete output issues // (e.g. UNICODE string will be NOT just corrupted as in case when we don't set setlocale() // but will break further normal output to console due to special characters being accidentally handled by console in the wrong way). //setlocale (LC_ALL, ".OCP"); // _O_U16TEXT can be used with fgetws() to get similar result as ReadConsoleW() without affecting setlocale(), // however it would break pipe input //_setmode (_fileno(stdin), _O_U16TEXT); bool isConsoleInput = true; for (;;) { while (console_semaphore != WAIT_CONSOLE_COMMAND) { Sleep (100); } const HANDLE anStdIn = ::GetStdHandle (STD_INPUT_HANDLE); if (anStdIn != NULL && anStdIn != INVALID_HANDLE_VALUE && isConsoleInput) { DWORD aNbRead = 0; if (ReadConsoleW (anStdIn, console_command, DRAW_COMMAND_SIZE, &aNbRead, NULL)) { console_command[aNbRead] = L'\0'; console_semaphore = HAS_CONSOLE_COMMAND; continue; } else { const DWORD anErr = GetLastError(); if (anErr != ERROR_SUCCESS) { // fallback using fgetws() which would work with pipes // but supports Unicode only through multi-byte encoding (which is not UTF-8) isConsoleInput = false; continue; } } } // fgetws() works only for characters within active locale (see setlocale()) if (fgetws (console_command, DRAW_COMMAND_SIZE, stdin)) { console_semaphore = HAS_CONSOLE_COMMAND; } } } /*--------------------------------------------------------*\ | exitProc: finalization handler for Tcl/Tk thread. Forces parent process to die \*--------------------------------------------------------*/ void exitProc(ClientData /*dc*/) { NCollection_List::Iterator Iter(MyCallbacks); for(; Iter.More(); Iter.Next()) { (*Iter.Value())(); } HANDLE proc = GetCurrentProcess(); TerminateProcess(proc, 0); } // This is fixed version of TclpGetDefaultStdChannel() defined in tclWinChan.c // See https://core.tcl.tk/tcl/tktview/91c9bc1c457fda269ae18595944fc3c2b54d961d static Tcl_Channel TclpGetDefaultStdChannel( int type) /* One of TCL_STDIN, TCL_STDOUT, or * TCL_STDERR. */ { Tcl_Channel channel; HANDLE handle; int mode = -1; const char *bufMode = NULL; DWORD handleId = (DWORD) -1; /* Standard handle to retrieve. */ switch (type) { case TCL_STDIN: handleId = STD_INPUT_HANDLE; mode = TCL_READABLE; bufMode = "line"; break; case TCL_STDOUT: handleId = STD_OUTPUT_HANDLE; mode = TCL_WRITABLE; bufMode = "line"; break; case TCL_STDERR: handleId = STD_ERROR_HANDLE; mode = TCL_WRITABLE; bufMode = "none"; break; default: Tcl_Panic("TclGetDefaultStdChannel: Unexpected channel type"); break; } handle = GetStdHandle(handleId); /* * Note that we need to check for 0 because Windows may return 0 if this * is not a console mode application, even though this is not a valid * handle. */ if ((handle == INVALID_HANDLE_VALUE) || (handle == 0)) { return (Tcl_Channel) NULL; } /* * Make duplicate of the standard handle as it may be altered * (closed, reopened with another type of the object etc.) by * the system or a user code at any time, e.g. by call to _dup2() */ if (! DuplicateHandle (GetCurrentProcess(), handle, GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { return (Tcl_Channel) NULL; } channel = Tcl_MakeFileChannel(handle, mode); if (channel == NULL) { return (Tcl_Channel) NULL; } /* * Set up the normal channel options for stdio handles. */ if (Tcl_SetChannelOption(NULL,channel,"-translation","auto")!=TCL_OK || Tcl_SetChannelOption(NULL,channel,"-eofchar","\032 {}")!=TCL_OK || Tcl_SetChannelOption(NULL,channel,"-buffering",bufMode)!=TCL_OK) { Tcl_Close(NULL, channel); return (Tcl_Channel) NULL; } return channel; } // helper functuion static void ResetStdChannel (int type) { Tcl_Channel aChannel = TclpGetDefaultStdChannel (type); Tcl_SetStdChannel (aChannel, type); if (aChannel) { Tcl_RegisterChannel (NULL, aChannel); } } /*--------------------------------------------------------*\ | tkLoop: implements Tk_Main()-like behaviour in a separate thread \*--------------------------------------------------------*/ static DWORD WINAPI tkLoop (const LPVOID theThreadParameter) { (void)theThreadParameter; Tcl_CreateExitHandler(exitProc, 0); Draw_Interpretor& aCommands = Draw::GetInterpretor(); aCommands.Init(); Tcl_Interp *interp = aCommands.Interp(); Tcl_Init(interp); // Work-around against issue with Tcl standard channels on Windows. // These channels by default use OS handles owned by the system which // may get invalidated e.g. by dup2() (see dlog command). // If this happens, output to stdout from Tcl (e.g. puts) gets broken // (sympthom is error message: "error writing "stdout": bad file number"). // To prevent this, we set standard channels using duplicate of system handles. // The effect is that Tcl channel becomes independent on C file descriptor // and even if stdout/stderr are redirected using dup2(), Tcl keeps using // original device. ResetStdChannel (TCL_STDOUT); ResetStdChannel (TCL_STDERR); #if (TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)) // Plain Tcl (8.6.4+) initializes interpretor channels automatically, but // ActiveState Tcl (at least 8.6.4) does not seem to do that, so channels // need to be set into interpretor explicitly { Tcl_Channel aChannelIn = Tcl_GetStdChannel (TCL_STDIN); Tcl_Channel aChannelOut = Tcl_GetStdChannel (TCL_STDOUT); Tcl_Channel aChannelErr = Tcl_GetStdChannel (TCL_STDERR); if (aChannelIn != NULL) { Tcl_RegisterChannel (aCommands.Interp(), aChannelIn); } if (aChannelOut != NULL) { Tcl_RegisterChannel (aCommands.Interp(), aChannelOut); } if (aChannelErr != NULL) { Tcl_RegisterChannel (aCommands.Interp(), aChannelErr); } } #endif #ifdef _TK // initialize the Tk library if not in 'virtual windows' mode // (virtual windows are created by OCCT with native APIs, // thus Tk will be useless) if (!Draw_VirtualWindows) { try { OCC_CATCH_SIGNALS Standard_Integer res = Tk_Init (interp); if (res != TCL_OK) { #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5))) std::cout << "tkLoop: error in Tk initialization. Tcl reported: " << Tcl_GetStringResult(interp) << std::endl; #else std::cout << "tkLoop: error in Tk initialization. Tcl reported: " << interp->result << std::endl; #endif } } catch (const Standard_Failure&) { std::cout << "tkLoop: exception in TK_Init\n"; } Tcl_StaticPackage (interp, "Tk", Tk_Init, (Tcl_PackageInitProc* ) NULL); mainWindow = Tk_MainWindow (interp); if (mainWindow == NULL) { #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5))) fprintf (stderr, "%s\n", Tcl_GetStringResult(interp)); #else fprintf (stderr, "%s\n", interp->result); #endif std::cout << "tkLoop: Tk_MainWindow() returned NULL. Exiting...\n"; Tcl_Exit (0); } Tk_Name(mainWindow) = Tk_GetUid (Tk_SetAppName (mainWindow, "Draw")); } #endif //#ifdef _TK // set signal handler in the new thread OSD::SetSignal(Standard_False); // inform the others that we have started isTkLoopStarted = true; while (console_semaphore == STOP_CONSOLE) Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT); if (Draw_IsConsoleSubsystem && console_semaphore == WAIT_CONSOLE_COMMAND) Prompt(interp, 0); //process a command Standard_Boolean toLoop = Standard_True; while (toLoop) { // The natural way is first flushing events, already put into queue, and then processing custom code in-between. // Unfortunately, Tcl has no API returning the number of queued events like XPending(), and only empty state can be checked. // Since events can be continuously fed from parallel threads, Tcl_DoOneEvent might never return empty state at all. const bool isTclEventQueueEmpty = Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT) == 0; if (console_semaphore == HAS_CONSOLE_COMMAND) { const TCollection_AsciiString aCmdUtf8 (console_command); const bool wasInterpreted = Draw_Interprete (aCmdUtf8.ToCString()); if (Draw_IsConsoleSubsystem) { Prompt (interp, wasInterpreted ? 0 : 1); } console_semaphore = WAIT_CONSOLE_COMMAND; } else if (isTclEventQueueEmpty) { // release CPU while polling Sleep (1); } #ifdef _TK // We should not exit until the Main Tk window is closed toLoop = (Draw_VirtualWindows || Tk_GetNumMainWindows() > 0); #endif } Tcl_Exit(0); return 0; } /*--------------------------------------------------------*\ | Run_Appli \*--------------------------------------------------------*/ void Run_Appli(HWND hWnd) { MSG msg; HACCEL hAccel = NULL; msg.wParam = 1; // if (!(hAccel = LoadAccelerators (hInstance, MAKEINTRESOURCE(ACCEL_ID)))) // MessageBox(hWnd, "MDI: Load Accel failure!", "Error", MB_OK); DWORD IDThread; HANDLE hThread; if (Draw_IsConsoleSubsystem) { hThread = CreateThread (NULL, // no security attributes 0, // use default stack size readStdinThreadFunc, // thread function NULL, // no thread function argument 0, // use default creation flags &IDThread); // returns thread identifier if (!hThread) { std::cout << "pb in creation of the thread reading stdin" << std::endl; Draw_IsConsoleSubsystem = Standard_False; Init_Appli (GetModuleHandleW (NULL), GetModuleHandleW (NULL), 1, hWnd); // reinit => create MDI client wnd } } //turn on the command interpretation mechanism (regardless of the mode) if (console_semaphore == STOP_CONSOLE) console_semaphore = WAIT_CONSOLE_COMMAND; //simple Win32 message loop while (GetMessageW (&msg, NULL, 0, 0) > 0) { if (!TranslateAcceleratorW (hWnd, hAccel, &msg)) { TranslateMessage (&msg); DispatchMessageW (&msg); } } ExitProcess(0); } /*--------------------------------------------------------*\ | Destroy_Appli \*--------------------------------------------------------*/ void Destroy_Appli(HINSTANCE hInst) { UnregisterAppClass(hInst); for (int i = 0 ; i < MAXCOLOR ; i++) DeleteObject(colorPenTab[i]); } /*--------------------------------------------------------*\ | SelectWait \*--------------------------------------------------------*/ void DrawWindow::SelectWait(HANDLE& hWnd, int& x, int& y, int& button) { MSG msg; msg.wParam = 1; GetMessageW (&msg, NULL, 0, 0); while((msg.message != WM_RBUTTONDOWN && msg.message != WM_LBUTTONDOWN) || ! ( Draw_IsConsoleSubsystem || IsChild(DrawWindow::hWndClientMDI,msg.hwnd)) ) { GetMessageW (&msg, NULL, 0, 0); } hWnd = msg.hwnd; x = LOWORD(msg.lParam); y = HIWORD(msg.lParam); if (msg.message == WM_LBUTTONDOWN) button = 1; else button = 3; } /*--------------------------------------------------------*\ | SelectNoWait \*--------------------------------------------------------*/ void DrawWindow::SelectNoWait(HANDLE& hWnd, int& x, int& y, int& button) { MSG msg; msg.wParam = 1; GetMessageW (&msg,NULL,0,0); while((msg.message != WM_RBUTTONDOWN && msg.message != WM_LBUTTONDOWN && msg.message != WM_MOUSEMOVE) || ! ( Draw_IsConsoleSubsystem || IsChild(DrawWindow::hWndClientMDI,msg.hwnd) ) ) { GetMessageW(&msg,NULL,0,0); } hWnd = msg.hwnd; x = LOWORD(msg.lParam); y = HIWORD(msg.lParam); switch (msg.message) { case WM_LBUTTONDOWN : button = 1; break; case WM_RBUTTONDOWN : button = 3; break; case WM_MOUSEMOVE : button = 0; break; } } Standard_Boolean DrawWindow::DefineColor (const Standard_Integer, const char*) { return Standard_True; } #endif