Three senses: * Tk within frame of other application (written in, for example, Visual C++). So far, only works--barely--with IE. * [Embedding Windows applications in Tk frames] * Tk application that also invokes, say, MFC widgets. This might involve, in particular, [Using MFC Controls as Tk widgets]. [Jeffrey Hobbs] and [David Gravereaux] know the most about these. None of them (except for MFC controls as widgets) really work as of January 2002 without a lot of fiddling ... [Arjen Markus] There may be a connection with [Drawing Into Foreign Windows]. [Frame] and [toplevel] bear on this topic. If an external X11 application has a command-line option to configure its placement (as, for example, xanim's +Wid), then mumble-mumble used with the -container of toplevel and frame. "man [winfo]" gives information on X11-id-s. Credit [Andreas Leitgeb] with this observation. [Theo Verelst] There ''is'' at least a connection with [tclhttpd] .. ----------------------------------------------------- placing the Tk widgets in IE has been simplified by using the TclControl activeX. Using the IE version 6.0, I have found it to be the most stable... TclControl can be found at: http://www.sys.uea.ac.uk/~fuzz/optcl/default.html I have made little to no changes to many Tcl/Tk apps that can run within the IE window... Yes you still need to have a copy of Tcl/Tk installed (but so does java requires a VM to be resident)...Of coarse you need to worry about security issues by allowing the activeX to access Tcl... James Garrison [[Explain tangential connections of [TclScript] and [GPS] work.]] ---- The point of TclScript is to plug in the Tcl '''language''' as an IE extension. This would mean that IE would be able to parse pages with the following type of script code:
This isn't quite the same as the ActiveX component which has more to do with placing a Tk toplevel widget onto the browser window and processing Tcl script within itself. Of course at present (Jan 2002) TclScript remains vapour-ware (or maybe liquid-ware as there is code, it's just not useable :) ) but I hope to find the time to continue at some point this year. [PT] ---- [NEM] '''19May2003''' - Here's a quick example of embedding an application into a Tk widget using [BLT]'s container and bgexec commands. The application being embedded in this case is Vim running in an Eterm under Linux. I tried quickly to get this working with xterm, but I couldn't, whereas Eterm played nicely. package require Tk package require BLT # Create a unique name for the new process set name "EmbedTk[pid][clock seconds]" eval blt::bgexec wait [list Eterm -n $name -e vi] $argv pack [blt::container .c -name $name] -fill both wm title . "Vim running in Tk" # Wait for app to exit (could use trace + callback here) vwait wait destroy . This allows you to embed the program based on it's name. The reason for using bgexec is that we need a method of detecting when the application has finished (yet it needs to run in the background), so that we can destroy the widget or do whatever. BTW, to use with xterm you have to change the "-n" switch to "-name". However, for some reason, this still didn't work. Note that resizing the widget won't resize the embedded window, so don't pack with -expand 1. ---- [DG] -- Here is a C++ example for how to use external windows as containers. Use [[[toplevel] -use ]] to attach to it. Notice the four special windows messages used for the "container protocol". #include HINSTANCE hInstance; class MainWnd { public: MainWnd(int nCmdShow); ~MainWnd(); HWND GetWindowId(); private: friend LRESULT CALLBACK MainWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); static bool first; int UserSizeChanging; HWND hMain; HWND hAttach; }; MainWnd::MainWnd (int nCmdShow) : hAttach(NULL), UserSizeChanging(0) { // do first time inits ? // if (first) { WNDCLASSEX wndcls; first = false; // register our StatBox window class // wndcls.cbSize = sizeof (WNDCLASSEX); wndcls.style = 0; wndcls.cbClsExtra = 0; wndcls.cbWndExtra = sizeof (HANDLE); wndcls.hInstance = hInstance; wndcls.hCursor = ::LoadCursor (NULL, IDC_ARROW); wndcls.lpszMenuName = NULL; wndcls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wndcls.hIcon = ::LoadIcon (NULL, IDI_APPLICATION); wndcls.hIconSm = ::LoadIcon (NULL, IDI_APPLICATION); wndcls.lpfnWndProc = MainWndProc; wndcls.lpszClassName = "TkFriendly"; ::RegisterClassEx (&wndcls); } hMain = ::CreateWindowEx ( WS_EX_LEFT, "TkFriendly", "Tk container protocol example.", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0L, 0L, hInstance, this ); ::ShowWindow(hMain, nCmdShow); ::UpdateWindow(hMain); } MainWnd::~MainWnd () { if (hMain) ::SendMessage(hMain, WM_CLOSE, 0, 0); } HWND MainWnd::GetWindowId() { return hMain; } bool MainWnd::first = true; LRESULT CALLBACK MainWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { MainWnd *pMain = reinterpret_cast (::GetWindowLongPtr(hwnd, GWLP_USERDATA)); switch (iMsg) { case WM_CREATE: // Supposedly, lpCreateParams has a DWORD alignment problem. // I don't know what this means for pointers. I doubt much. // pMain = reinterpret_cast (((LPCREATESTRUCT)lParam)->lpCreateParams); // move the MainWnd class pointer into the // userdata of the window. // ::SetWindowLongPtr (hwnd, GWLP_USERDATA, reinterpret_cast (pMain)); return 0; case WM_CLOSE: ::DestroyWindow(hwnd); return 0; case WM_DESTROY: pMain->hMain = NULL; delete pMain; ::PostQuitMessage(0); return 0; // --------- Begin Tk container specials ---------- #define TK_CLAIMFOCUS (WM_USER) #define TK_GEOMETRYREQ (WM_USER+1) #define TK_ATTACHWINDOW (WM_USER+2) #define TK_DETACHWINDOW (WM_USER+3) case TK_CLAIMFOCUS: if (wParam || (GetFocus() != NULL)) { ::SetFocus(pMain->hAttach); } return 0; case TK_GEOMETRYREQ: if (!pMain->UserSizeChanging) { /* * Make the client area to be the size given, but * we move the whole window. Calc the additions * to get us there. */ wParam += 2 * GetSystemMetrics(SM_CXEDGE) + 3; lParam += GetSystemMetrics(SM_CYCAPTION) + (2 * GetSystemMetrics(SM_CYEDGE) + 3); ::SetWindowPos(hwnd, NULL, 0, 0, wParam, lParam, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); } return 0; case TK_ATTACHWINDOW: pMain->hAttach = (HWND)wParam; ::SetParent(pMain->hAttach, hwnd); return 0; case TK_DETACHWINDOW: pMain->hAttach = NULL; ::PostMessage(hwnd, WM_CLOSE, 0, 0); return 0; // --------- End Tk container specials ---------- case WM_ENTERSIZEMOVE: pMain->UserSizeChanging = 1; break; case WM_EXITSIZEMOVE: pMain->UserSizeChanging = 0; break; case WM_SIZE: if (wParam != SIZE_MINIMIZED && pMain->hAttach) { ::SetWindowPos(pMain->hAttach, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); } return 0; case WM_PARENTNOTIFY: switch (LOWORD(wParam)) { case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: ::SetFocus(pMain->hAttach); return 0; case WM_DESTROY: ::PostQuitMessage(0); return 0; } break; case WM_ERASEBKGND: if (pMain->UserSizeChanging) return 1; break; } return ::DefWindowProc(hwnd, iMsg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) { MSG msg; MainWnd *main; char buf[50]; main = new MainWnd(nCmdShow); wsprintf(buf, "%ld", main->GetWindowId()); MessageBox(main->GetWindowId(), buf, "Window ID is:", MB_OK); while (::GetMessage(&msg, NULL, 0, 0)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } return msg.wParam; } There's a problem when this technique is used in-process regarding resizing. No solution is known at this time. ---- [Category GUI]