//
// 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 version 2.1 as published
+// 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.
// commercial license or contractual agreement.
// include windows.h first to have all definitions available
-#ifdef WNT
+#ifdef _WIN32
#include <windows.h>
#endif
#include <tcl.h>
#include <Draw_Interpretor.hxx>
+#include <Draw_Window.hxx>
#include <Draw_Appli.hxx>
#include <TCollection_AsciiString.hxx>
+#include <TCollection_ExtendedString.hxx>
#include <Image_AlienPixMap.hxx>
+#include <NCollection_List.hxx>
-extern Draw_Interpretor theCommands;
+extern Standard_Boolean Draw_Batch;
extern Standard_Boolean Draw_VirtualWindows;
-static Tcl_Interp *interp; /* Interpreter for this application. */
+static NCollection_List<Draw_Window::FCallbackBeforeTerminate> MyCallbacks;
+
+void Draw_Window::AddCallbackBeforeTerminate(FCallbackBeforeTerminate theCB)
+{
+ MyCallbacks.Append(theCB);
+}
+
+void Draw_Window::RemoveCallbackBeforeTerminate(FCallbackBeforeTerminate theCB)
+{
+ NCollection_List<Draw_Window::FCallbackBeforeTerminate>::Iterator Iter(MyCallbacks);
+ for(; Iter.More(); Iter.Next())
+ {
+ if (Iter.Value() == theCB)
+ {
+ MyCallbacks.Remove(Iter);
+ break;
+ }
+ }
+}
/*
*----------------------------------------------------------------------
static void Prompt(Tcl_Interp *Interp, int partial)
{
-
- // MKV 29.03.05
-#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
- const char *promptCmd;
-#else
- char *promptCmd;
-#endif
- int code;
- Tcl_Channel outChannel, errChannel;
- outChannel = Tcl_GetStdChannel(TCL_STDOUT);
- promptCmd = Tcl_GetVar(Interp,(char*)
- (partial ? "tcl_prompt2" : "tcl_prompt1"), TCL_GLOBAL_ONLY);
-
+ 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 {
- code = Tcl_Eval(Interp, promptCmd);
+ int code = Tcl_Eval(Interp, promptCmd);
outChannel = Tcl_GetStdChannel(TCL_STDOUT);
errChannel = Tcl_GetStdChannel(TCL_STDERR);
if (code != TCL_OK) {
#if !defined(_WIN32) && !defined(__WIN32__)
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#include <OSD_Timer.hxx>
-
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-#ifdef HAVE_SYS_FILIO_H
-#include <sys/filio.h>
-#else
-#include <sys/ioctl.h>
-#endif
-
-#include <fcntl.h>
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
#include <Draw_Window.hxx>
-
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
-
-#include <stdio.h>
+#include <unistd.h>
#if defined(__APPLE__) && !defined(MACOSX_USE_GLX)
// use forward declaration for small subset of used Tk functions
* terminal-like device. Zero means it's
* a file. */
-static unsigned long thePixels[MAXCOLOR];
-
Standard_Integer Draw_WindowScreen = 0;
Standard_Boolean Draw_BlackBackGround = Standard_True;
#include <X11/Xutil.h>
#include <Aspect_DisplayConnection.hxx>
+static unsigned long thePixels[MAXCOLOR];
+
Display* Draw_WindowDisplay = NULL;
Colormap Draw_WindowColorMap;
static Handle(Aspect_DisplayConnection) Draw_DisplayConnection;
// 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;
//function : SetTitle
//purpose :
//=======================================================================
-void Draw_Window::SetTitle(const char* title)
+void Draw_Window::SetTitle(const TCollection_AsciiString& theTitle)
{
- XStoreName(Draw_WindowDisplay, win, title);
+ XStoreName (Draw_WindowDisplay, win, theTitle.ToCString());
}
//=======================================================================
//function : GetTitle
//purpose :
//=======================================================================
-char* Draw_Window::GetTitle()
+TCollection_AsciiString Draw_Window::GetTitle() const
{
- char* title;
- XFetchName(Draw_WindowDisplay, win, &title);
- return title;
+ char* aTitle = NULL;
+ XFetchName (Draw_WindowDisplay, win, &aTitle);
+ return TCollection_AsciiString (aTitle);
}
//=======================================================================
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 :
Image_AlienPixMap anImage;
bool isBigEndian = Image_PixMap::IsBigEndianHost();
const Standard_Size aSizeRowBytes = Standard_Size(winAttr.width) * 4;
- if (!anImage.InitTrash (isBigEndian ? Image_PixMap::ImgRGB32 : Image_PixMap::ImgBGR32,
+ if (!anImage.InitTrash (isBigEndian ? Image_Format_RGB32 : Image_Format_BGR32,
Standard_Size(winAttr.width), Standard_Size(winAttr.height), aSizeRowBytes))
{
return Standard_False;
XComposeStatus stat;
char chainekey[10];
-
- switch (xev.type) {
-
+ 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;
#endif
- if (tty) Prompt(theCommands.Interp(), 0);
- Prompt(theCommands.Interp(), 0);
+ Draw_Interpretor& aCommands = Draw::GetInterpretor();
+
+ if (tty) Prompt(aCommands.Interp(), 0);
+ Prompt(aCommands.Interp(), 0);
outChannel = Tcl_GetStdChannel(TCL_STDOUT);
if (outChannel) {
if (Draw_VirtualWindows) {
// main window will never shown
// but main loop will parse all Xlib messages
- Tcl_Eval(theCommands.Interp(), "wm withdraw .");
+ Tcl_Eval(aCommands.Interp(), "wm withdraw .");
}
Tk_MainLoop();
}
#endif
+ NCollection_List<Draw_Window::FCallbackBeforeTerminate>::Iterator Iter(MyCallbacks);
+ for(; Iter.More(); Iter.Next())
+ {
+ (*Iter.Value())();
+ }
}
//======================================================
//======================================================
Standard_Boolean Init_Appli()
{
- theCommands.Init();
- interp = theCommands.Interp();
+ Draw_Interpretor& aCommands = Draw::GetInterpretor();
+ aCommands.Init();
+ Tcl_Interp *interp = aCommands.Interp();
+ Tcl_Init (interp);
- Tcl_Init(interp) ;
try {
OCC_CATCH_SIGNALS
Tk_Init(interp) ;
*/
prompt:
- if (tty) Prompt(interp, gotPartial);
+ if (tty) Prompt(Draw::GetInterpretor().Interp(), gotPartial);
} catch (Standard_Failure) {}
HWND DrawWindow::CreateDrawWindow(HWND hWndClient, int nitem)
{
if (Draw_IsConsoleSubsystem) {
- HWND aWin = CreateWindow (DRAWCLASS, DRAWTITLE,
+ HWND aWin = CreateWindowW (DRAWCLASS, DRAWTITLE,
WS_OVERLAPPEDWINDOW,
1,1,1,1,
NULL, NULL,::GetModuleHandle(NULL), NULL);
return aWin;
}
else {
- HANDLE hInstance;
-#ifndef _WIN64
- hInstance = (HANDLE)GetWindowLong(hWndClient,GWL_HINSTANCE);
-#else
- hInstance = (HANDLE)GetWindowLong(hWndClient,GWLP_HINSTANCE);
-#endif
+ HANDLE hInstance = (HANDLE )GetWindowLongPtrW (hWndClient, GWLP_HINSTANCE);
- return CreateMDIWindow(DRAWCLASS, DRAWTITLE,
+ return CreateMDIWindowW(DRAWCLASS, DRAWTITLE,
WS_CAPTION | WS_CHILD | WS_THICKFRAME,
1,1,0,0,
hWndClient, (HINSTANCE)hInstance, nitem);
\*--------------------------------------------------------*/
LRESULT APIENTRY DrawWindow::DrawProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
{
- DrawWindow* localObjet = (DrawWindow*)GetWindowLong(hWnd, CLIENTWND);
+ 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:
{
- if (Draw_IsConsoleSubsystem)
- return (DefWindowProc(hWnd, wMsg, wParam, lParam));
+ 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
- return(DefMDIChildProc(hWnd, wMsg, wParam, lParam));
+ {
+ localObjet->WExpose();
+ }
+ EndPaint (hWnd, &ps);
+ return 0;
}
-
- PAINTSTRUCT ps;
-
- switch(wMsg)
- {
- case WM_PAINT :
- BeginPaint(hWnd, &ps);
- if (localObjet->GetUseBuffer())
- localObjet->Redraw();
- else
- localObjet->WExpose();
- EndPaint(hWnd, &ps);
- return 0l;
- break;
-
- case WM_SIZE:
- if (localObjet->GetUseBuffer()) {
- localObjet->InitBuffer();
- localObjet->WExpose();
- localObjet->Redraw();
- return 0l;
+ case WM_SIZE:
+ {
+ if (localObjet->GetUseBuffer())
+ {
+ localObjet->InitBuffer();
+ localObjet->WExpose();
+ localObjet->Redraw();
+ return 0;
+ }
+ break;
}
-
- default:
- if (Draw_IsConsoleSubsystem)
- return (DefWindowProc(hWnd, wMsg, wParam, lParam));
- else
- return(DefMDIChildProc(hWnd, wMsg, wParam, lParam));
}
+ return Draw_IsConsoleSubsystem
+ ? DefWindowProcW (hWnd, wMsg, wParam, lParam)
+ : DefMDIChildProcW (hWnd, wMsg, wParam, lParam);
}
}
//________________________
-DrawWindow::DrawWindow(char* title,
+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)
Init(X, Y, dX, dY);
SetTitle(title);
}
-DrawWindow::DrawWindow(char* title,
+DrawWindow::DrawWindow(const char* title,
Standard_Integer X, Standard_Integer Y,
Standard_Integer dX,Standard_Integer dY,
HWND theWin) :
// include decorations in the window dimensions
// to reproduce same behaviour of Xlib window.
- DWORD aWinStyle = GetWindowLong (win, GWL_STYLE);
- DWORD aWinStyleEx = GetWindowLong (win, GWL_EXSTYLE);
+ DWORD aWinStyle = GetWindowLongW (win, GWL_STYLE);
+ DWORD aWinStyleEx = GetWindowLongW (win, GWL_EXSTYLE);
HMENU aMenu = GetMenu (win);
RECT aRect;
SetPosition (aRect.left, aRect.top);
SetDimension (aRect.right - aRect.left, aRect.bottom - aRect.top);
// Save the pointer at the instance associated to the window
- SetWindowLong(win, CLIENTWND, (LONG)this);
+ SetWindowLongPtrW (win, CLIENTWND, (LONG_PTR)this);
HDC hDC = GetDC(win);
SetBkColor(hDC, RGB(0, 0, 0));
myCurrPen = 3;
GetClientRect(win, &rc);
if (myMemHbm) {
BITMAP aBmp;
- GetObject(myMemHbm, sizeof(BITMAP), &aBmp);
+ GetObjectW (myMemHbm, sizeof(BITMAP), &aBmp);
if (rc.right-rc.left == aBmp.bmWidth && rc.bottom-rc.top == aBmp.bmHeight) return;
DeleteObject(myMemHbm);
}
\*--------------------------------------------------------*/
void DrawWindow::SetPosition(Standard_Integer posX, Standard_Integer posY)
{
- SetWindowPos(win, 0,
- posX, posY,
- 0, 0,
- SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
+ UINT aFlags = SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER;
+ if (Draw_VirtualWindows)
+ {
+ aFlags |= SWP_NOSENDCHANGING;
+ }
+ SetWindowPos (win, 0, posX, posY, 0, 0, aFlags);
}
\*--------------------------------------------------------*/
void DrawWindow::SetDimension(Standard_Integer dimX, Standard_Integer dimY)
{
- SetWindowPos(win, 0,
- 0, 0,
- dimX, dimY,
- SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
+ UINT aFlags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER;
+ if (Draw_VirtualWindows)
+ {
+ aFlags |= SWP_NOSENDCHANGING;
+ }
+ SetWindowPos (win, 0, 0, 0, dimX, dimY, aFlags);
}
/*--------------------------------------------------------*\
| SetTitle
\*--------------------------------------------------------*/
-void DrawWindow::SetTitle(char* title)
+void DrawWindow::SetTitle (const TCollection_AsciiString& theTitle)
{
- SetWindowText(win, title);
+ const TCollection_ExtendedString aTitleW (theTitle);
+ SetWindowTextW (win, aTitleW.ToWideString());
}
/*--------------------------------------------------------*\
| GetTitle
-| Attention do not forget to unallocate the memory
\*--------------------------------------------------------*/
-char* DrawWindow::GetTitle()
+TCollection_AsciiString DrawWindow::GetTitle() const
{
- char* title=new char[31];
- GetWindowText(win, title, 30);
- return title;
+ 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
{
// Get informations about the bitmap
BITMAP aBitmap;
- if (GetObject (theHBitmap, sizeof(BITMAP), (LPSTR )&aBitmap) == 0)
+ if (GetObjectW (theHBitmap, sizeof(BITMAP), &aBitmap) == 0)
{
return Standard_False;
}
Image_AlienPixMap anImage;
- const Standard_Size aSizeRowBytes = Standard_Size(aBitmap.bmWidth) * 4;
- if (!anImage.InitTrash (Image_PixMap::ImgBGR32, Standard_Size(aBitmap.bmWidth), Standard_Size(aBitmap.bmHeight), aSizeRowBytes))
+ 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;
}
aBitmapInfo.biWidth = aBitmap.bmWidth;
aBitmapInfo.biHeight = aBitmap.bmHeight; // positive means bottom-up!
aBitmapInfo.biPlanes = 1;
- aBitmapInfo.biBitCount = 32; // use 32bit for automatic word-alignment per row
+ aBitmapInfo.biBitCount = 24;
aBitmapInfo.biCompression = BI_RGB;
// Copy the pixels
HDC hDC = GetDC(win);
HDC aWorkDC = myUseBuffer ? GetMemDC(hDC) : hDC;
- TextOut(aWorkDC, x, y, text, (int )strlen(text));
+ TCollection_ExtendedString textW (text);
+ TextOutW(aWorkDC, x, y, (const wchar_t*)textW.ToExtString(), (int )strlen(text));
if (myUseBuffer) ReleaseMemDC(aWorkDC);
ReleaseDC(win,hDC);
//* threads sinchronization *//
DWORD dwMainThreadId;
console_semaphore_value volatile console_semaphore = WAIT_CONSOLE_COMMAND;
-//char console_command[1000];
-#define COMMAND_SIZE 1000 /* Console Command size */
-char console_command[COMMAND_SIZE];
+wchar_t console_command[DRAW_COMMAND_SIZE + 1];
bool volatile isTkLoopStarted = false;
/*--------------------------------------------------------*\
DWORD IDThread;
HANDLE hThread;
console_semaphore = STOP_CONSOLE;
- theCommands.Init();
- interp = theCommands.Interp();
- Tcl_Init(interp) ;
dwMainThreadId = GetCurrentThreadId();
0, // use default creation flags
&IDThread);
if (!hThread) {
- cout << "Tcl/Tk main loop thread not created. Switching to batch mode..." << endl;
+ cout << "Failed to create Tcl/Tk main loop thread. Switching to batch mode..." << 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) {
- cout <<" Pb au lancement de TK_Init "<<endl;
+ Tk_Init(interp);
+ } catch (Standard_Failure& anExcept) {
+ cout << "Failed to initialize Tk: " << anExcept.GetMessageString() << endl;
}
Tcl_StaticPackage(interp, "Tk", Tk_Init, (Tcl_PackageInitProc *) NULL);
/*--------------------------------------------------------*\
| readStdinThreadFunc
\*--------------------------------------------------------*/
-static DWORD WINAPI readStdinThreadFunc(VOID)
+static DWORD WINAPI readStdinThreadFunc()
{
- if (!Draw_IsConsoleSubsystem) return 1;
- for(;;) {
+ 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);
- if (fgets(console_command,COMMAND_SIZE,stdin))
+ {
+ 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;
+ }
}
}
\*--------------------------------------------------------*/
void exitProc(ClientData /*dc*/)
{
+ NCollection_List<Draw_Window::FCallbackBeforeTerminate>::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(VOID)
{
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))
- Tcl_RegisterChannel(theCommands.Interp(), Tcl_GetStdChannel(TCL_STDIN));
- Tcl_RegisterChannel(theCommands.Interp(), Tcl_GetStdChannel(TCL_STDOUT));
- Tcl_RegisterChannel(theCommands.Interp(), Tcl_GetStdChannel(TCL_STDERR));
+ // 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
#endif //#ifdef _TK
// set signal handler in the new thread
- OSD::SetSignal();
+ OSD::SetSignal(Standard_False);
// inform the others that we have started
isTkLoopStarted = true;
while(Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT));
if (console_semaphore == HAS_CONSOLE_COMMAND)
{
- if (Draw_Interprete (console_command))
+ TCollection_AsciiString aCmdUtf8 (console_command);
+ if (Draw_Interprete (aCmdUtf8.ToCString()))
{
if (Draw_IsConsoleSubsystem) Prompt (interp, 0);
}
}
#ifdef _TK
// We should not exit until the Main Tk window is closed
- toLoop = (Tk_GetNumMainWindows() > 0) || Draw_VirtualWindows;
+ toLoop = (Draw_VirtualWindows || Tk_GetNumMainWindows() > 0);
#endif
}
Tcl_Exit(0);
if (!hThread) {
cout << "pb in creation of the thread reading stdin" << endl;
Draw_IsConsoleSubsystem = Standard_False;
- Init_Appli(GetModuleHandle(NULL),
- GetModuleHandle(NULL),
- 1, hWnd); // reinit => create MDI client wnd
+ Init_Appli (GetModuleHandleW (NULL),
+ GetModuleHandleW (NULL),
+ 1, hWnd); // reinit => create MDI client wnd
}
}
console_semaphore = WAIT_CONSOLE_COMMAND;
//simple Win32 message loop
- while (GetMessage(&msg, NULL, 0, 0) > 0)
+ while (GetMessageW (&msg, NULL, 0, 0) > 0)
{
- if (!TranslateAccelerator(hWnd, hAccel, &msg))
+ if (!TranslateAcceleratorW (hWnd, hAccel, &msg))
{
- TranslateMessage(&msg);
- DispatchMessage(&msg);
+ TranslateMessage (&msg);
+ DispatchMessageW (&msg);
}
}
ExitProcess(0);
msg.wParam = 1;
- GetMessage(&msg,NULL,0,0);
+ GetMessageW (&msg, NULL, 0, 0);
while((msg.message != WM_RBUTTONDOWN && msg.message != WM_LBUTTONDOWN) ||
! ( Draw_IsConsoleSubsystem || IsChild(DrawWindow::hWndClientMDI,msg.hwnd)) )
- GetMessage(&msg,NULL,0,0);
+ {
+ GetMessageW (&msg, NULL, 0, 0);
+ }
hWnd = msg.hwnd;
x = LOWORD(msg.lParam);
msg.wParam = 1;
- GetMessage(&msg,NULL,0,0);
+ 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) ) )
- GetMessage(&msg,NULL,0,0);
+ {
+ GetMessageW(&msg,NULL,0,0);
+ }
hWnd = msg.hwnd;
x = LOWORD(msg.lParam);
y = HIWORD(msg.lParam);