Redirecting cout to a TextBuffer

View: New views
8 Messages — Rating Filter:   Alert me  

Redirecting cout to a TextBuffer

by Søren Hauberg-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi all,
  I'm using gtksourceviewmm as terminal-like widget, and I want to
redirect std::cout to this widget. Currently I'm doing something like
this in my constructor:

    std::ostringstream outs;
    std::cout.rdbuf (outs.rdbuf ());

and then I have a function 'update' that looks something like this

    bool update (int timer_number)
     {
       // Update text output
       buffer->insert (buffer->end(), outs.str ());
       outs.str (""); // Empty stream

       return true;
     }

this function is then called on a reglar basis using a
'Glib::signal_timeout'. This works, but the timer has to have a very
high frequency if the output should appear smoothly. So, I'm not
really a fan of this approach. Can I somehow redirect 'std::cout'
directly to the TextBuffer?

Thanks,
Søren
_______________________________________________
gtkmm-list mailing list
gtkmm-list@...
http://mail.gnome.org/mailman/listinfo/gtkmm-list

Re: Redirecting cout to a TextBuffer

by milosz derezynski :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I guess you should set up a watch on stdout using Glib::IOChannel. I'm not sure how to do this for C++ streams since the IOChannel API, while wrapped into C++, still operates on C FDs only, but this would solve the problem.

2008/5/10 Søren Hauberg <hauberg@...>:
Hi all,
 I'm using gtksourceviewmm as terminal-like widget, and I want to
redirect std::cout to this widget. Currently I'm doing something like
this in my constructor:

   std::ostringstream outs;
   std::cout.rdbuf (outs.rdbuf ());

and then I have a function 'update' that looks something like this

   bool update (int timer_number)
    {
      // Update text output
      buffer->insert (buffer->end(), outs.str ());
      outs.str (""); // Empty stream

      return true;
    }

this function is then called on a reglar basis using a
'Glib::signal_timeout'. This works, but the timer has to have a very
high frequency if the output should appear smoothly. So, I'm not
really a fan of this approach. Can I somehow redirect 'std::cout'
directly to the TextBuffer?

Thanks,
Søren
_______________________________________________
gtkmm-list mailing list
gtkmm-list@...
http://mail.gnome.org/mailman/listinfo/gtkmm-list


_______________________________________________
gtkmm-list mailing list
gtkmm-list@...
http://mail.gnome.org/mailman/listinfo/gtkmm-list

Re: Redirecting cout to a TextBuffer

by Søren Hauberg-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

2008/5/10 Milosz Derezynski <internalerror@...>:
> I guess you should set up a watch on stdout using Glib::IOChannel. I'm not
> sure how to do this for C++ streams since the IOChannel API, while wrapped
> into C++, still operates on C FDs only, but this would solve the problem.
Thanks, I'll try that. Is such an approach portable? I mean, does it
work on Windows?

Søren
_______________________________________________
gtkmm-list mailing list
gtkmm-list@...
http://mail.gnome.org/mailman/listinfo/gtkmm-list

Re: Redirecting cout to a TextBuffer

by milosz derezynski :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I don't really know anything about Windows programming but i'd imagine the Windows C runtime offers an stdout and stderr the same way as under *nix.

2008/5/11 Søren Hauberg <hauberg@...>:
2008/5/10 Milosz Derezynski <internalerror@...>:
> I guess you should set up a watch on stdout using Glib::IOChannel. I'm not
> sure how to do this for C++ streams since the IOChannel API, while wrapped
> into C++, still operates on C FDs only, but this would solve the problem.
Thanks, I'll try that. Is such an approach portable? I mean, does it
work on Windows?

Søren


_______________________________________________
gtkmm-list mailing list
gtkmm-list@...
http://mail.gnome.org/mailman/listinfo/gtkmm-list

Re: Redirecting cout to a TextBuffer

by Charles McLachlan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Sat, 10 May 2008, Søren Hauberg wrote:

> Hi all,
>  I'm using gtksourceviewmm as terminal-like widget, and I want to
> redirect std::cout to this widget. Currently I'm doing something like
> this in my constructor:
>
>    std::ostringstream outs;
>    std::cout.rdbuf (outs.rdbuf ());

Caveat: I don't know much about gtksourcemm but I do know something about
STL streambufs.

If the above code works (its an interesting idea that I have not seen
before), then my advice would be subclass your own streambuf. You'll need
to overload the the sync and overflow members. These have slightly weird
actions and (on first viewing) appear non trivial.

The advantage of this appreoach is that the source view will only be
updated when 1) the buffer runs out, 2) the stream explicitly asks for it,
usually via stream.sync() being called. This (correctly) puts the control
of the updates in the hands of the user of the stream, rather than having
to wait for timeouts.

Here is an (untested) example based on a streambuf I wrote for encoding
streams into base64,

class ogsbuf : public std::streambuf
{
public:
  const static int kZBufferSize = 2048;
  typedef unsigned char char_type;
  typedef int int_type;
  typedef std::streampos pos_type;
  typedef std::streamoff off_type;

  private:
  gtksourceviewmm *destination;
  unsigned char buffer[kZBufferSize];

  public:

  explicit ogsbuf(gtksourceviewmm *_destination) : destination(_destinination) {
  setp((char *)buffer, (char *)buffer + kZBufferSize);
  }

  ~ogsbuf() { sync(); }

protected:
  inline int sync()
  {
  // pbase() is an unsigned char * pointing to the data to be written to the destination
  // pptr() is an end pointer for the data.
  // pptr() - pbase() is the length of the data in the buffer
  destination->append(pbase(), pbase() - pptr());

  setp((char *)buffer, (char *)buffer + kZBufferSize);

  return 0;
  };

  inline int overflow(int ch = traits_type::eof())
  {
  int ret = sync();
  *pptr() = ch;
  pbump(1);
  return ret;
  };
};

Then do

ogsbuf  gsb(ptrToSourceView);
std::cout.rdbuf (gsb);


Charlie - Metropolis Data Consultants - 07976 028167 - 01223 763758

_______________________________________________
gtkmm-list mailing list
gtkmm-list@...
http://mail.gnome.org/mailman/listinfo/gtkmm-list

Re: Redirecting cout to a TextBuffer

by Charles McLachlan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Sun, 11 May 2008, Milosz Derezynski wrote:

> I don't really know anything about Windows programming but i'd imagine the
> Windows C runtime offers an stdout and stderr the same way as under *nix.

Oh, if that were true everyone would be a lot happier.

It depends on which flags you give the compiler.

I use mingw32 to cross compile. If you give it -mwindows you don't get
stdout/stderr/stdin and you also don't get a nasty empty console window
when you invoke the program from Explorer.

What actually happens when you try to use stderr/stdout from a -mwindows
program also varies depending on version of mingw and version of windows.
Sometimes your bytes just get ignored, sometimes an exception is raised,
sometimes the program tight loops, sometimes it burns your toast and
scares your cat.

Charlie - Metropolis Data Consultants - 07976 028167 - 01223 763758

_______________________________________________
gtkmm-list mailing list
gtkmm-list@...
http://mail.gnome.org/mailman/listinfo/gtkmm-list

Re: Redirecting cout to a TextBuffer

by Søren Hauberg-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

2008/5/12 Charles McLachlan <cim20@...>:
> If the above code works (its an interesting idea that I have not seen
> before), then my advice would be subclass your own streambuf. You'll need to
> overload the the sync and overflow members. These have slightly weird
> actions and (on first viewing) appear non trivial.

I haven't had the time to actually implement this, but it seems just
like the approach I was looking for.

Thanks,
Søren
_______________________________________________
gtkmm-list mailing list
gtkmm-list@...
http://mail.gnome.org/mailman/listinfo/gtkmm-list

Re: Redirecting cout to a TextBuffer

by Søren Hauberg-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

2008/5/12 Charles McLachlan <cim20@...>:

> On Sat, 10 May 2008, Søren Hauberg wrote:
>
>> Hi all,
>>  I'm using gtksourceviewmm as terminal-like widget, and I want to
>> redirect std::cout to this widget. Currently I'm doing something like
>> this in my constructor:
>>
>>   std::ostringstream outs;
>>   std::cout.rdbuf (outs.rdbuf ());
>
> Caveat: I don't know much about gtksourcemm but I do know something about
> STL streambufs.
>
> If the above code works (its an interesting idea that I have not seen
> before), then my advice would be subclass your own streambuf. You'll need to
> overload the the sync and overflow members. These have slightly weird
> actions and (on first viewing) appear non trivial.
>
> The advantage of this appreoach is that the source view will only be updated
> when 1) the buffer runs out, 2) the stream explicitly asks for it, usually
> via stream.sync() being called. This (correctly) puts the control of the
> updates in the hands of the user of the stream, rather than having to wait
> for timeouts.

So, I finally got my act together and implemented your idea, so I
thought I'd report back. Basically, your idea works great. Some
modifications were necessary, so I thought I'd post the code in case
anybody wanted something similar:

class ogsbuf : public std::streambuf
{
private:
  const static int kZBufferSize = 2048;
  Glib::RefPtr<Gtk::TextBuffer> destination;
  char *buffer;

public:
  explicit ogsbuf (Glib::RefPtr<Gtk::TextBuffer> &_destination)
   : destination (_destination)
  {
    buffer = (char*)malloc (sizeof (char) * kZBufferSize);
    setp (buffer, buffer + kZBufferSize);
  }

  ~ogsbuf ()
  {
    sync ();
    clear ();
  }

  void clear ()
  {
    free (buffer);
  }

protected:
  inline int sync()
  {
    // pbase () is an unsigned char * pointing to the data to be
written to the destination
    // pptr () is an end pointer for the data.
    destination->insert (destination->end (), pbase (), pptr ());
    setp (buffer, buffer + kZBufferSize);

    return 0;
  }

  inline int overflow (int ch = traits_type::eof ())
  {
    const int ret = sync ();
    *pptr () = ch;
    pbump (1);
    return ret;
  }
};

Thanks,
Søren
_______________________________________________
gtkmm-list mailing list
gtkmm-list@...
http://mail.gnome.org/mailman/listinfo/gtkmm-list