Logo Search packages:      
Sourcecode: vdkbuilder2 version File versions  Download package

vdkb_maker.cc

#if HAVE_CONFIG_H
#include <config.h>
#endif

#if !HAVE_GNOME
  #if ENABLE_NLS
    #include <libintl.h>
//#define _(str) gettext(str)
#define _(str) \
    ( g_utf8_validate(gettext(str),-1,NULL) ? \
    gettext(str) : \
    g_locale_to_utf8(gettext(str),-1,NULL,NULL,NULL) )
#define N_(str) str
  #else
    #define _(str) str
    #define N_(str) str 
  #endif
#else
 #include <gnome.h>
#endif

#include <vdkb2/vdkb_maker.h>
#include <vdkb2/vdkb.h>
#define IO_BUFF_SIZE 65536

extern char *gear_xpm[];
static char *maker_kill_xpm[] =
{
"16 14 4 1",
"a c #7f7f7f",
"b c #000000",
". c None",
"# c #ff0000",
"................",
"...........#....",
"...##a....###...",
"....##a..#####..",
".....#######bb..",
"......#####b....",
"......####b.....",
".....######.....",
".....##b.###....",
"....##b...###...",
"....#b.....##a..",
"...#b.......#b..",
"...b.........b..",
"................"};

VDKBMaker *VDKBMaker::self; // a little trick to make reaper works
static char *buff;
static char *line;
//////////////////////////////////////////
DEFINE_SIGNAL_MAP(VDKBMaker,VDKForm)
  ON_SIGNAL(inp1,INP_SIGNAL,DoIO),
  ON_SIGNAL(inp2,INP_SIGNAL,DoIO),
  ON_SIGNAL(toolbar,clicked_signal,HandleToolbar),
  ON_SIGNAL(text,realize_signal,OnTextRealize),
  ON_SIGNAL(errtext,realize_signal,OnTextRealize)
END_SIGNAL_MAP       

//////////////////// RESPONSE /////////////////////
/*
  cast white background to override some gtk-themes defaults
*/
bool
VDKBMaker::OnTextRealize(VDKObject* sender)
{
  VDKTextView *obj = dynamic_cast<VDKTextView*>(sender);
  if(obj)
    obj->NormalBackground = clWhite;
  return true;
}
/*
 */
bool
VDKBMaker::HandleToolbar(VDKObject*)
{
int button = toolbar->ButtonPressed;
switch(button)
  {
  case 0:
    runcmd();
    break;
  case 1:
    quit();
    break;
  }
return true;
}

/*
reaper, called at sigaction SIGCHILD
(child finished or stopped)
 */
void VDKBMaker::reaper(int)
{
  int sts;
  int pid;
  //  sigset_t set, oldset;  
  VDKBMaker* form = (VDKBMaker*) VDKBMaker::self;
  pid = waitpid(-1, &sts, WNOHANG);
  if(pid == ((VDKBMaker*)self)->Pid())
    { 
      form->Pid(0); 
      form->ChildStatus(sts);
    }
#if 0
        // If we have another pid or something
    else if(pid == form->Sib())
      //...
#endif

  /* re-install the signal handler (some systems need this) */ 
      // signal(SIGCHLD, VDKBMaker::reaper); 
  /* and unblock it */ 
      // sigemptyset(&set); 
      // sigaddset(&set, SIGCHLD); 
      // sigprocmask(SIG_UNBLOCK, &set, &oldset); 
}

/*
  This routine scrolls last line
  of text.
*/
static void Scroll(VDKTextView *text)
{
  /* 
  GtkTextView* logwin = GTK_TEXT(text->WrappedWidget());
  GtkAdjustment *logadj = GTK_TEXT(text->WrappedWidget())->vadj;
  gint pos = gtk_text_get_length(logwin);
  gtk_text_freeze(logwin);
  gtk_editable_insert_text(GTK_EDITABLE(logwin), " ", 1, &pos);
  gtk_text_thaw(logwin);
  gtk_adjustment_set_value(logadj, logadj->upper - logadj->page_size);
  */
}
/*
 */  
bool VDKBMaker::DoIO (VDKObject *obj)
{
  VDKBMainForm* ownerform;
  VDKInput *ip = static_cast<VDKInput*>(obj);
  int res;
  res = read (ip->getfd(), buff, IO_BUFF_SIZE);
  if(res > 0)
    {
      if(ip == inp1) // STDOUT
      {
        if(outlist == 1) // load messages from stdout
          {
            char *q;
            *(buff+res) = 0;             // safety
            if((q = strchr(buff,'\n')))
            { 
              strcat(line,buff);
              // add error to errlist
              errlist->add(line);
              *line = '\0';
            }
            else
            strcat(line,buff);

          }
        text->TextInsert(buff, res);
        // scroll to last line
        Scroll(text);
      }
      else //STDERR
        {
        if(outlist == 0) // load messages from stderr
          {   
            char *q;
            *(buff+res) = 0;             // safety
            if((q = strchr(buff,'\n')))
            { 
              strcat(line,buff);
              // add error to errlist
              errlist->add(line);
              *line = '\0';
            }
            else
            strcat(line,buff);
          }
        errtext->TextInsert(buff);
        // scroll to last line
        Scroll(errtext);
      }
        
    }
  else // no more inputs
    { 
      ip->release();
      close(ip->getfd());
      if(ip == inp1) // STDOUT
      io &= ~IO_STDOUT;
      else // STDERR
      io &= ~IO_STDERR;
      if(io == 0)   // Closed both channnels
      {
      bool isIconized;
      time_t t;
      time(&t);
      ownerform = (VDKBMainForm*) Owner();
      isIconized = ownerform->Iconized;
      if(isIconized)
        {
          ownerform->SetIconized(false);
          ChildListIterator li(ownerform->Childs());
          for(;li;li++)
            if(li.current() != this)
            li.current()->SetIconized(false);
        }
      sprintf(buff,_("DONE with result %d, at %s\n"), status, ctime(&t));
      text->TextInsert(buff);
      (*toolbar)[NEW_PROJECT_BUTTON]->Enabled = true;
      if(! IsModal())
        Close();
      } 
    }
  return true;
}

//////////////////////////////////////////////////
VDKBMaker::VDKBMaker(VDKForm* owner, char **args,VDKBStringList* list,
                 bool hide_on_run, int outlist):
          VDKForm(owner,"VDKBuilder Maker"), args(args), errlist(list),
        hide_on_run(hide_on_run),outlist(outlist)
{
  buff = new char[IO_BUFF_SIZE];
  line = new char[IO_BUFF_SIZE];
}

void
VDKBMaker::runcmd(void)
{
  VDKBMainForm* ownerform;
  *line = '\0';
  errlist->flush();
  if(io == IO_NONE)
    {
      int ch1[2], ch2[2];
      // creates pipe pairs
      pipe(ch1);
      pipe(ch2);
      // forks child
      pid = fork();

      switch(pid)
        {
      case 0:
        close(0);
        dup2(ch1[1], 1);
        dup2(ch2[1], 2);
        execvp(args[0], args);
        break;
      case -1:
        break;
      default:
        text->Clear();
        errtext->Clear();
        close(ch1[1]);      // Important! Close my end here
        close(ch2[1]);      // Important! Close my end here
        // Set pipes none blocking, so we can read big buffers
        // in the callback without having to use FIONREAD
        // to make sure the callback doesn't block.
        int md;
        if((md = fcntl(ch1[0], F_GETFL)) != -1)
          fcntl(ch1[0], F_SETFL, O_NONBLOCK | md );
        
        if((md = fcntl(ch2[0], F_GETFL)) != -1)
          fcntl(ch2[0], F_SETFL, O_NONBLOCK | md );
        // VDKInput was modified to allow connecting to a new 
        // stream, because the Destroy() method caused a GTK+ 
        // error as the gtk+ widget was NULL.
        // bug fixed by mario now (01.10.1999)
        if(inp1)
          inp1->connect(ch1[0]);
        else
          inp1 = new VDKInput(this,ch1[0]);
        if(inp2)
          inp2->connect(ch2[0]);
        else
          inp2 = new VDKInput(this,ch2[0]);
        io |= (IO_STDERR|IO_STDOUT);
        // start owner timer
        ownerform = (VDKBMainForm*) Owner();
        // disable "begin"
        (*toolbar)[0]->Enabled = false;
        // iconize builder (and all builder childs)
        if(hide_on_run)
          {
            ownerform->SetIconized(true);
            ChildListIterator li(ownerform->Childs());
            for(;li;li++)
            if(li.current() != this)
              li.current()->SetIconized(true);
          }
        break;
        }
    }
  return ;
}
/*
 */
bool VDKBMaker::CanClose(void)  
{
  if(pid)
    {
      Application()->VDKMessageBox(APPNAME,
      _("A compilation process is running;\nkill it before close"),
                        VDK_ICONINFORMATION|VDK_OK,
                        _(user_messages[user_ok]),
                        NULL,
                        3000);
      return false;
    }
  if(buff)     delete[] buff; 
  if(line)     delete[] line; 
  return true; 
}

/*
 */
void 
VDKBMaker:: quit()
{
  if(pid)
    kill(pid, SIGTERM);
  else
    Close();
}

/*
 */
void VDKBMaker::Setup(void)
{
  VDKBMaker::self = this;
  //
  inp1 = 0;
  inp2 = 0;
  pid = 0;
  io = IO_NONE;
  //
  struct sigaction *sac = new struct sigaction;
  sigemptyset(&(sac->sa_mask));
  sac->sa_flags=0;
  sac->sa_handler = VDKBMaker::reaper;
  sigaction(SIGCHLD, sac, NULL);  

  //  signal(SIGCHLD, VDKBMaker::reaper); 

  toolbar = new VDKToolbar(this);
  toolbar->Borderless = true;
  toolbar->Style = GTK_TOOLBAR_ICONS;
  // toolbar->Spacing = 20;
  toolbar->AddButton(gear_xpm,
                 _(vdkbmaker_prompts[1]), 
                 _(vdkbmaker_prompts[0]));
  // toolbar->AddSpace();
  toolbar->AddButton(maker_kill_xpm,
                 _(vdkbmaker_prompts[3]),
                 _(vdkbmaker_prompts[2])
                 );
  toolbar->Borderless = true;
  Add(toolbar,l_justify,false,false,0);
  // a separator
  Add(new VDKSeparator(this,h_separator),false,false,2);
  // a pane that contains stdout and stderr
  VDKPaned* paned = new VDKPaned(this);
  // VDKBox* panedbox = new VDKBox(this);
  // displays stdout
  text = new VDKTextView(this);
  if(VDKRgb("navy blue").IsValid())
    text->Foreground = VDKRgb("navy blue"); 
  text->SetSize(450,200);
  paned->Add(text,1);
  // panedbox->Add(text);
  // displays stderr
  errtext = new VDKTextView(this);
  if(clSiena.IsValid())
    errtext->Foreground = VDKRgb(clSiena);  
  errtext->SetSize(450,50);
  paned->Add(errtext,2);
  // panedbox->Add(errtext);
  // 
  Add(paned);
  // Add(panedbox);

}

void 
VDKBMaker::OnShow(VDKForm*)
{
  // running command directly when form is showed
  // sometimes hangs on Async replay by x server
  // uncomment this if you have problems.
  runcmd();
}

Generated by  Doxygen 1.6.0   Back to index