octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Questions about the pager


From: John Swensen
Subject: Re: Questions about the pager
Date: Thu, 18 Jan 2007 10:38:32 -0500
User-agent: Thunderbird 1.5.0.9 (Macintosh/20061207)

John W. Eaton wrote:
On  7-Nov-2006, John Swensen wrote:

| John W. Eaton wrote:
| > On  6-Nov-2006, John Swensen wrote:
| >
| > | John Swensen wrote:
| > | > I recently have discovered the my IDE fails when the pager is turned | > | > on. I think I have narrowed down the problem, but need advice from | > | > someone with more UNIXy PTY experience than I. I am using the patch | > | > that JWE pointed me to, which I modified per the maintainers request | > | > and re-submitted to the VTE. It allows me to make the IDE and octave | > | > the same process. I am not 100% sure exactly how it works, other than | > | > the fact that I open a new pseudo-TTY and attach the master side to | > | > the VTE widget and run octave inside the pseudo-TTY using the | > | > following function run as a thread.
| > | >
| > | > void* octave_main_wrapper(void *dummy)
| > | > {
| > | >  // TODO: pass in the real argc, argv
| > | >  int argc = 1;
| > | >  char* argv[] = {"/usr/bin/octave"};
| > | >  octave_main(argc,argv,0);
| > | >
| > | >  do_octave_atexit();
| > | >
| > | >  cout << "Exiting Octave - debug CTRL-C" << endl;
| > | >
| > | >  return 0;
| > | > }
| > | >
| > | > The problem seems to arise when the pager is called. I think this is | > | > because Octave is actually spawning an instance of 'less' and for some | > | > reason it is attached to the TTY of the terminal from which I ran | > | > octave, rather than being attached to the pseudo-TTY in which Octave | > | > is running. Can anyone give some advice on this issue? Namely, is | > | > there a way to make the pager run inside the same pseudo-TTY as the | > | > octave process.
| > | >
| > | > John Swensen
| > | >
| > | I would like to amend this statement. In fact, the pager output does | > | show up in the VTE window, it is the input to the pager that must come | > | from the original terminal from which I launched my IDE. So, forward, | > | back, quit, nor CTRL-C works from the VTE window, but they do work from | > | the original terminal.
| >
| > Look at the source to less.  In the file ttyin.c, it opens /dev/tty to
| > get input from the user.  I think the reason for this is that if less
| > is invoked like this:
| >
| >   some_command | less
| >
| > then it can't use stdin to read user commands from the keyboard
| > becuase stdin is already connected to the source for the text it is
| > displaying.
| >
| > Isn't the VTE widget used to implement gnome-terminal?  What does it
| > do to connect to /dev/tty when it has the window manager focus?
| >
| > jwe
| >
| > | After investigating a little further, I have discovered the following. | The patch to VTE was intended such that the IDE and octave would show up | as a single process. Otherwise, it would be just like gnome-terminal | and bash, where each time gnome-terminal is started, an instance of bash | is also started. This was done by creating a pseudoTTY(PTY) and | attaching it to VTE, then running Octave in the new PTY. I'm not 100% | sure on this, but I think I am pretty much out of luck to get this | working with the current way of doing things. I am going to run a very | simple test to see if it acts differently between using the VTE | fork_pty() and set_pty() function. I suspect the fork_pty() will work | as expected, but set_pty() won't. So, I can see at least 2 solutions to | this problem (but others may see much better ones) | 1) Since the IDE has scrollback, just make sure paging is off when | octave is running in the IDE | 2) Somehow set up my IDE as an external pager and handle it myself (very | undesirable, because 'less' is good at what it does) | 3) Some other method of redirecting the input channel from the VTE to | the file descriptors from the popen() call. (Also probably won't be easy). | | Any other suggested solutions?

Yes, if you are still interested, I think something like the following
will help:

  /* dissociate from the controlling terminal, if any */

  pid_t pid = fork ();

  if (pid < 0)
    {
      fprintf (stderr, "fork failed\n");
      return 1;
    }
  else if (pid == 0)
    {
      /* child */
      fprintf (stderr, "in child, calling setsid ()\n");

      if (setsid () < 0)
        {
          fprintf (stderr, "setsid error\n");
          return 1;
        }
    }
  else
    {
      /* parent */
      fprintf (stderr, "in parent, exiting\n");
      exit (0);
    }

This works for me.  Without it, less is looking for input from the
terminal window where I start the vte program.  With these lines, less
works as expected.

I'm attaching my complete example below.  Compile and run it and type
"ls" at the prompt.  That will cause

  system ("ls -lR /dev | less")

to be executed, and then you should be able to interact with less.

BTW, I see that that thanks to your work, vte_terminal_set_pty has now
been included in libvte, so the following program works for me on a
current Debian testing system without needing to build a customized
version of libvte.  Thanks.

jwe


------------------------------------------------------------------------

/*

compile with:

  gcc -g $(pkg-config gtk+-2.0 --cflags) main.c -o main \
      -lvte $(pkg-config gtk+-2.0 --libs)  -lreadline -lpthread -lutil

*/

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <gtk/gtk.h>
#include <vte/vte.h>
#include <pthread.h>
#include <pty.h>

#include <readline/readline.h>
#include <readline/history.h>

void
execute_line (char *line)
{
  static char *err_hilite_on = "\e[01;31m";
  static char *err_hilite_off = "\e[0m";

  if (! strcmp (line, "ls"))
    system ("ls -lR /dev | less");
  else if (! strcmp (line, "quit"))
    exit (0);
  else
    fprintf (stderr, "%sunknown command `%s'%s\n",
             err_hilite_on, line, err_hilite_off);
}

void *
fileman_main (void *dummy)
{
  rl_readline_name = "FileMan";

  /* Loop reading and executing lines until the user quits. */
  while (1)
    {
      char *line = readline ("FileMan: ");

      if (! line)
        break;

      if (*line)
        {
          add_history (line);
          execute_line (line);
        }
      else
        free (line);
    }

  return 0;
}

int
main (int argc, char **argv)
{
  pthread_t fileman_thread;

  int fdm;
  int fds;

  /* GtkWidget is the storage type for widgets */
  GtkWidget *window;
  GtkWidget *terminal;

  /* dissociate from the controlling terminal, if any */

  pid_t pid = fork ();

  if (pid < 0)
    {
      fprintf (stderr, "fork failed\n");
      return 1;
    }
  else if (pid == 0)
    {
      /* child */
      fprintf (stderr, "in child, calling setsid ()\n");

      if (setsid () < 0)
        {
          fprintf (stderr, "setsid error\n");
          return 1;
        }
    }
  else
    {
      /* parent */
      fprintf (stderr, "in parent, exiting\n");
      exit (0);
    }
/* This is called in all GTK applications. Arguments are parsed
   * from the command line and are returned to the application. */
  gtk_init (&argc, &argv);

  /* create a new window */
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

  terminal = vte_terminal_new ();

  if (openpty (&fdm, &fds, 0, 0, 0) < 0)
    fprintf (stderr, "oops!\n");

  dup2 (fds, 0);
  dup2 (fds, 1);
  dup2 (fds, 2);

  pthread_create (&fileman_thread, 0, fileman_main, 0);

  vte_terminal_set_pty (VTE_TERMINAL (terminal), fdm);

  /* This packs the terminal into the window (a gtk container). */
  gtk_container_add (GTK_CONTAINER (window), terminal);

  vte_terminal_set_font_from_string (VTE_TERMINAL (terminal), "Fixed 11");

  vte_terminal_set_size (VTE_TERMINAL (terminal), 80, 24);

  vte_terminal_set_scrollback_lines (VTE_TERMINAL (terminal), 1024);

  /* The final step is to display this newly created widget. */
  gtk_widget_show (terminal);

  /* and the window */
  gtk_widget_show (window);

  /* All GTK applications must have a gtk_main(). Control ends here
   * and waits for an event to occur (like a key press or
   * mouse event). */
  gtk_main ();

  return 0;
}
I was still interested, and that was the perfect solution. The rest of my code was taken from your previous example on the list a couple of months back. All I had to do was add the fork and subsequent checks for child/parent. Thank you very much. That was one of the existing bugs that made the IDE somewhat unusable. I will get that checked in as soon as possible.

John Swensen


reply via email to

[Prev in Thread] Current Thread [Next in Thread]