Version 1 of Drawing Into Foreign Windows

Updated 2001-12-28 03:50:50

George Peter Staplin: Someone asked me how to draw into a foreign window today, and I've wondered how to do it for a while, so I came up with the working solution below. It works well if you just need to display some canvas data in another window. I'm not quite sure how to make buttons or canvas objects displayed in the foreign window respond to keyboard and mouse events. Also for most needs wish -use xid, and/or toplevel -use xid will work well if you want to use another X window as a parent for the Tk window.-


  #include <stdlib.h>
  #include <stdio.h>
  #include <tcl.h>
  #include <tk.h>

  Tk_Window wmain;
  Tk_Window canvas;
  int depth;
  Display *display;
  Colormap colormap;
  Tcl_Interp *interp;
  Window root;


  int draw_test_cmd (ClientData clientData, Tcl_Interp *interp, \
        int argc, char *argv[])
  {
  Tk_Window button;
  Tk_Window canvas;
  Window oldButton;
  Window oldCanvas;
        char drawStr[] = "
        .c create polygon 200 10 300 200 100 200 -fill blue -tag square1
        update
        ";


  button = Tk_NameToWindow (interp, ".f.b", wmain);
  canvas = Tk_NameToWindow (interp, ".c", wmain);

  oldButton = (((Tk_FakeWin *) (button))->window);
  oldCanvas = (((Tk_FakeWin *) (canvas))->window);

  (((Tk_FakeWin *) (button))->window) = root;
  (((Tk_FakeWin *) (canvas))->window) = root;

        if (Tcl_Eval (interp, drawStr) != TCL_OK) {
        fprintf (stderr, "%s", Tcl_GetStringResult);
        return TCL_ERROR;
        }

  (((Tk_FakeWin *) (button))->window) = oldButton;
  (((Tk_FakeWin *) (canvas))->window) = oldCanvas;

  return TCL_OK;
  }


  int app_init (Tcl_Interp *interp) {
        char tinit[] = "
        pack [frame .f] -fill x
        pack [button .f.b -text Go -command draw_test_cmd;]
        wm geometry . 400x400
        pack [canvas .c -height 200 -width 200] -fill both -expand yes
        update
        bind .c <Expose> draw_test_cmd        
        bind .c <Configure> draw_test_cmd
        ";


        if (Tcl_Init (interp) != TCL_OK) {
        fprintf (stderr, "%s", Tcl_GetStringResult (interp));
        exit (0);
        }

        if (Tk_Init (interp) != TCL_OK) {
        fprintf (stderr, "%s", Tcl_GetStringResult (interp));
        exit (0);
        }


  Tcl_CreateCommand (interp, "draw_test_cmd", draw_test_cmd, \
        (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);


  wmain = Tk_MainWindow (interp);
  display = Tk_Display (wmain);
  Tk_MakeWindowExist (wmain);
  Tk_MapWindow (wmain);

  depth = Tk_Depth (wmain);

  root = RootWindow (display, DefaultScreen (display));

  colormap = DefaultColormap (display, 0);

        if (Tcl_Eval (interp, tinit) != TCL_OK) {
        fprintf (stderr, "%s", Tcl_GetStringResult (interp));
        return TCL_ERROR;
        }


  canvas = Tk_NameToWindow (interp, ".c", wmain);
  Tk_MakeWindowExist (canvas);
  Tk_MapWindow (canvas);

  Tcl_Eval (interp, "");        

        while (Tk_GetNumMainWindows () > 0) {
        Tcl_DoOneEvent (0);
        }

  return TCL_OK;
  } 


  int main (int argc, char *argv[]) {

  Tk_Main (argc, argv, app_init);

  }