Blame support/cltkMain.c

Packit bd2e5d
/***********************************************************************/
Packit bd2e5d
/*                                                                     */
Packit bd2e5d
/*                 MLTk, Tcl/Tk interface of OCaml                     */
Packit bd2e5d
/*                                                                     */
Packit bd2e5d
/*    Francois Rouaix, Francois Pessaux, Jun Furuse and Pierre Weis    */
Packit bd2e5d
/*               projet Cristal, INRIA Rocquencourt                    */
Packit bd2e5d
/*            Jacques Garrigue, Kyoto University RIMS                  */
Packit bd2e5d
/*                                                                     */
Packit bd2e5d
/*  Copyright 2002 Institut National de Recherche en Informatique et   */
Packit bd2e5d
/*  en Automatique and Kyoto University.  All rights reserved.         */
Packit bd2e5d
/*  This file is distributed under the terms of the GNU Library        */
Packit bd2e5d
/*  General Public License, with the special exception on linking      */
Packit bd2e5d
/*  described in file LICENSE found in the OCaml source tree.          */
Packit bd2e5d
/*                                                                     */
Packit bd2e5d
/***********************************************************************/
Packit bd2e5d
Packit bd2e5d
/* $Id$ */
Packit bd2e5d
Packit bd2e5d
#include <string.h>
Packit bd2e5d
#include <tcl.h>
Packit bd2e5d
#include <tk.h>
Packit bd2e5d
#include <mlvalues.h>
Packit bd2e5d
#include <memory.h>
Packit bd2e5d
#include <alloc.h>
Packit bd2e5d
#include <callback.h>
Packit bd2e5d
#include <signals.h>
Packit bd2e5d
#include <fail.h>
Packit bd2e5d
#ifdef HAS_UNISTD
Packit bd2e5d
#include <unistd.h>  /* for R_OK */
Packit bd2e5d
#endif
Packit bd2e5d
#include "camltk.h"
Packit bd2e5d
Packit bd2e5d
#ifndef R_OK
Packit bd2e5d
#define R_OK 4
Packit bd2e5d
#endif
Packit bd2e5d
Packit bd2e5d
/*
Packit bd2e5d
 * Dealing with signals: when a signal handler is defined in OCaml,
Packit bd2e5d
 * the actual execution of the signal handler upon reception of the
Packit bd2e5d
 * signal is delayed until we are sure we are out of the GC.
Packit bd2e5d
 * If a signal occurs during the MainLoop, we would have to wait
Packit bd2e5d
 *  the next event for the handler to be invoked.
Packit bd2e5d
 * The following function will invoke a pending signal handler if any,
Packit bd2e5d
 * and we put in on a regular timer.
Packit bd2e5d
 */
Packit bd2e5d
Packit bd2e5d
#define SIGNAL_INTERVAL 300
Packit bd2e5d
Packit bd2e5d
int signal_events = 0; /* do we have a pending timer */
Packit bd2e5d
Packit bd2e5d
void invoke_pending_caml_signals (ClientData clientdata)
Packit bd2e5d
{
Packit bd2e5d
  signal_events = 0;
Packit bd2e5d
  caml_enter_blocking_section(); /* triggers signal handling */
Packit bd2e5d
  /* Rearm timer */
Packit bd2e5d
  Tk_CreateTimerHandler(SIGNAL_INTERVAL, invoke_pending_caml_signals, NULL);
Packit bd2e5d
  signal_events = 1;
Packit bd2e5d
  caml_leave_blocking_section();
Packit bd2e5d
}
Packit bd2e5d
Packit bd2e5d
/* Now the real Tk stuff */
Packit bd2e5d
Packit bd2e5d
Tk_Window cltk_mainWindow;
Packit bd2e5d
Packit bd2e5d
Packit bd2e5d
/* In slave mode, the interpreter *already* exists */
Packit bd2e5d
int cltk_slave_mode = 0;
Packit bd2e5d
Packit bd2e5d
/* Initialisation, based on tkMain.c */
Packit bd2e5d
CAMLprim value camltk_opentk(value argv)
Packit bd2e5d
{
Packit bd2e5d
  CAMLparam1(argv);
Packit bd2e5d
  CAMLlocal1(tmp);
Packit bd2e5d
  char *argv0;
Packit bd2e5d
Packit bd2e5d
  /* argv must contain argv[0], the application command name */
Packit bd2e5d
  tmp = Val_unit;
Packit bd2e5d
Packit bd2e5d
  if ( argv == Val_int(0) ){
Packit bd2e5d
    caml_failwith("camltk_opentk: argv is empty");
Packit bd2e5d
  }
Packit bd2e5d
  argv0 = String_val( Field( argv, 0 ) );
Packit bd2e5d
Packit bd2e5d
  if (!cltk_slave_mode) {
Packit bd2e5d
    /* Create an interpreter, dies if error */
Packit bd2e5d
#if TCL_MAJOR_VERSION >= 8
Packit bd2e5d
    Tcl_FindExecutable(String_val(argv0));
Packit bd2e5d
#endif
Packit bd2e5d
    cltclinterp = Tcl_CreateInterp();
Packit bd2e5d
    {
Packit bd2e5d
      /* Register cltclinterp for use in other related extensions */
Packit bd2e5d
      value *interp = caml_named_value("cltclinterp");
Packit bd2e5d
      if (interp != NULL)
Packit bd2e5d
        Store_field(*interp,0,caml_copy_nativeint((intnat)cltclinterp));
Packit bd2e5d
    }
Packit bd2e5d
Packit bd2e5d
    if (Tcl_Init(cltclinterp) != TCL_OK)
Packit bd2e5d
      tk_error(Tcl_GetStringResult(cltclinterp));
Packit bd2e5d
    Tcl_SetVar(cltclinterp, "argv0", String_val (argv0), TCL_GLOBAL_ONLY);
Packit bd2e5d
Packit bd2e5d
    { /* Sets argv */
Packit bd2e5d
      int argc = 0;
Packit bd2e5d
Packit bd2e5d
      tmp = Field(argv, 1); /* starts from argv[1] */
Packit bd2e5d
      while ( tmp != Val_int(0) ) {
Packit bd2e5d
        argc++;
Packit bd2e5d
        tmp = Field(tmp, 1);
Packit bd2e5d
      }
Packit bd2e5d
Packit bd2e5d
      if( argc != 0 ){
Packit bd2e5d
        int i;
Packit bd2e5d
        char *args;
Packit bd2e5d
        char **tkargv;
Packit bd2e5d
        char argcstr[256]; /* string of argc */
Packit bd2e5d
Packit bd2e5d
        tkargv = (char**)caml_stat_alloc(sizeof( char* ) * argc );
Packit bd2e5d
        tmp = Field(argv, 1); /* starts from argv[1] */
Packit bd2e5d
        i = 0;
Packit bd2e5d
Packit bd2e5d
        while ( tmp != Val_int(0) ) {
Packit bd2e5d
          tkargv[i] = String_val(Field(tmp, 0));
Packit bd2e5d
          tmp = Field(tmp, 1);
Packit bd2e5d
          i++;
Packit bd2e5d
        }
Packit bd2e5d
Packit bd2e5d
        sprintf( argcstr, "%d", argc );
Packit bd2e5d
        Tcl_SetVar(cltclinterp, "argc", argcstr, TCL_GLOBAL_ONLY);
Packit bd2e5d
        args = Tcl_Merge(argc, (const char *const*)tkargv); /* args must be freed by Tcl_Free */
Packit bd2e5d
        Tcl_SetVar(cltclinterp, "argv", args, TCL_GLOBAL_ONLY);
Packit bd2e5d
        Tcl_Free(args);
Packit bd2e5d
        caml_stat_free( tkargv );
Packit bd2e5d
      }
Packit bd2e5d
    }
Packit bd2e5d
    if (Tk_Init(cltclinterp) != TCL_OK)
Packit bd2e5d
      tk_error(Tcl_GetStringResult(cltclinterp));
Packit bd2e5d
Packit bd2e5d
    /* Retrieve the main window */
Packit bd2e5d
    cltk_mainWindow = Tk_MainWindow(cltclinterp);
Packit bd2e5d
Packit bd2e5d
    if (NULL == cltk_mainWindow)
Packit bd2e5d
      tk_error(Tcl_GetStringResult(cltclinterp));
Packit bd2e5d
Packit bd2e5d
    Tk_GeometryRequest(cltk_mainWindow,200,200);
Packit bd2e5d
  }
Packit bd2e5d
Packit bd2e5d
  /* Create the camlcallback command */
Packit bd2e5d
  Tcl_CreateCommand(cltclinterp,
Packit bd2e5d
                    CAMLCB, CamlCBCmd,
Packit bd2e5d
                    (ClientData)NULL,(Tcl_CmdDeleteProc *)NULL);
Packit bd2e5d
Packit bd2e5d
  /* This is required by "unknown" and thus autoload */
Packit bd2e5d
  Tcl_SetVar(cltclinterp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
Packit bd2e5d
  /* Our hack for implementing break in callbacks */
Packit bd2e5d
  Tcl_SetVar(cltclinterp, "BreakBindingsSequence", "0", TCL_GLOBAL_ONLY);
Packit bd2e5d
Packit bd2e5d
  /* Load the traditional rc file */
Packit bd2e5d
  {
Packit bd2e5d
    char *home = getenv("HOME");
Packit bd2e5d
    if (home != NULL) {
Packit bd2e5d
      char *f = caml_stat_alloc(strlen(home)+strlen(RCNAME)+2);
Packit bd2e5d
      f[0]='\0';
Packit bd2e5d
      strcat(f, home);
Packit bd2e5d
      strcat(f, "/");
Packit bd2e5d
      strcat(f, RCNAME);
Packit bd2e5d
      if (0 == access(f,R_OK))
Packit bd2e5d
        if (TCL_OK != Tcl_EvalFile(cltclinterp,f)) {
Packit bd2e5d
          caml_stat_free(f);
Packit bd2e5d
          tk_error(Tcl_GetStringResult(cltclinterp));
Packit bd2e5d
        };
Packit bd2e5d
      caml_stat_free(f);
Packit bd2e5d
    }
Packit bd2e5d
  }
Packit bd2e5d
Packit bd2e5d
  CAMLreturn(Val_unit);
Packit bd2e5d
}
Packit bd2e5d
Packit bd2e5d
CAMLprim value camltk_finalize(value unit) /* ML */
Packit bd2e5d
{
Packit bd2e5d
  Tcl_Finalize();
Packit bd2e5d
  return Val_unit;
Packit bd2e5d
}