diff options
author | Tim Moore <timoore@redhat.com> | 2009-12-09 22:09:39 +0100 |
---|---|---|
committer | Tim Moore <timoore@redhat.com> | 2009-12-09 22:09:39 +0100 |
commit | 3e1613e1f7ab589089e8ed5a504330bb9cb128db (patch) | |
tree | cc2a639738801467b52dad823d2eb4e2b187bf4e | |
parent | f4ba7c13533b7e99edd0e66a0f6ccd6c0f55ec38 (diff) | |
download | systemtap-steved-3e1613e1f7ab589089e8ed5a504330bb9cb128db.tar.gz systemtap-steved-3e1613e1f7ab589089e8ed5a504330bb9cb128db.tar.xz systemtap-steved-3e1613e1f7ab589089e8ed5a504330bb9cb128db.zip |
show the status of stap processes in the process window
Also, the "kill" button now works.
* grapher/StapParser.hxx (_ioConnection, _errIoConnection): new
members for sigc connections.
(initIo): New function
(parsers, parserListChangedSignal): new variables
* grapher/StapParser.cxx (ioCallback): disconnect signals when child
dies
(initIo): new function
* grapher/grapher.cxx (StapLauncher): eliminate death callback in
favor of childDied signal. Use global parsers list
(ProcWindow::_listSelection): new member
(ProcWindow::show, hide, onParserListChanged, onSelectionChanged,
onKill): new functions
(ProcWindow::ProcWindow): Set up cell renderer for status icon
* grapher/processwindow.glade: labels for display script and stap arguments
-rw-r--r-- | grapher/StapParser.cxx | 338 | ||||
-rw-r--r-- | grapher/StapParser.hxx | 8 | ||||
-rw-r--r-- | grapher/grapher.cxx | 167 | ||||
-rw-r--r-- | grapher/processwindow.glade | 132 |
4 files changed, 418 insertions, 227 deletions
diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx index b82cc024..a9a5109a 100644 --- a/grapher/StapParser.cxx +++ b/grapher/StapParser.cxx @@ -30,7 +30,15 @@ namespace systemtap static sigc::signal<void, pid_t> deathSignal; return deathSignal; } - + + ParserList parsers; + + sigc::signal<void>& parserListChangedSignal() + { + static sigc::signal<void> listChangedSignal; + return listChangedSignal; + } + vector<string> commaSplit(const boost::sub_range<Glib::ustring>& range) { using namespace boost; @@ -72,171 +80,173 @@ vector<string> commaSplit(const boost::sub_range<Glib::ustring>& range) } bool StapParser::ioCallback(Glib::IOCondition ioCondition) - { - using namespace std; - using std::tr1::shared_ptr; - using namespace boost; - if (ioCondition & Glib::IO_HUP) - { - childDiedSignal().emit(getPid()); - return true; - } - if ((ioCondition & Glib::IO_IN) == 0) + { + using namespace std; + using std::tr1::shared_ptr; + using namespace boost; + if (ioCondition & Glib::IO_HUP) + { + childDiedSignal().emit(getPid()); + _ioConnection.disconnect(); + _errIoConnection.disconnect(); + return true; + } + if ((ioCondition & Glib::IO_IN) == 0) + return true; + char buf[256]; + ssize_t bytes_read = 0; + bytes_read = read(_inFd, buf, sizeof(buf) - 1); + if (bytes_read <= 0) + { + childDiedSignal().emit(getPid()); return true; - char buf[256]; - ssize_t bytes_read = 0; - bytes_read = read(_inFd, buf, sizeof(buf) - 1); - if (bytes_read <= 0) - { - childDiedSignal().emit(getPid()); - return true; - } - _buffer.append(buf, bytes_read); - string::size_type ret = string::npos; - while ((ret = _buffer.find(_lineEndChar)) != string::npos) - { - Glib::ustring dataString(_buffer, 0, ret); - // %DataSet and %CSV declare a data set; all other - // statements begin with the name of a data set. - // Except %LineEnd :) - sub_range<Glib::ustring> found; - if (dataString[0] == '%') - { - if ((found = find_first(dataString, "%DataSet:"))) - { - string setName; - int hexColor; - double scale; - string style; - istringstream stream(Glib::ustring(found.end(), - dataString.end())); - stream >> setName >> scale >> std::hex >> hexColor - >> style; - if (style == "bar" || style == "dot") - { - std::tr1::shared_ptr<GraphData<double> > - dataSet(new GraphData<double>); - dataSet->name = setName; - if (style == "dot") - dataSet->style = &GraphStyleDot::instance; - dataSet->color[0] = (hexColor >> 16) / 255.0; - dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; - dataSet->color[2] = (hexColor & 0xff) / 255.0; - dataSet->scale = scale; - _dataSets.insert(std::make_pair(setName, dataSet)); - getGraphData().push_back(dataSet); - graphDataSignal().emit(); - } - else if (style == "discreet") - { - std::tr1::shared_ptr<GraphData<string> > - dataSet(new GraphData<string>); - dataSet->name = setName; - dataSet->style = &GraphStyleEvent::instance; - dataSet->color[0] = (hexColor >> 16) / 255.0; - dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; - dataSet->color[2] = (hexColor & 0xff) / 255.0; - dataSet->scale = scale; - _dataSets.insert(std::make_pair(setName, dataSet)); - getGraphData().push_back(dataSet); - graphDataSignal().emit(); - } - } - else if ((found = find_first(dataString, "%CSV:"))) - { - vector<string> tokens - = commaSplit(sub_range<Glib::ustring>(found.end(), - dataString.end())); - for (vector<string>::iterator tokIter = tokens.begin(), - e = tokens.end(); - tokIter != e; - ++tokIter) - { - DataMap::iterator setIter = _dataSets.find(*tokIter); - if (setIter != _dataSets.end()) - _csv.elements - .push_back(CSVData::Element(*tokIter, - setIter->second)); - } - } - else if ((found = find_first(dataString, "%LineEnd:"))) - { - istringstream stream(Glib::ustring(found.end(), - dataString.end())); - int charAsInt = 0; - // parse hex and octal numbers too - stream >> std::setbase(0) >> charAsInt; - _lineEndChar = static_cast<char>(charAsInt); - } - else - { - cerr << "Unknown declaration " << dataString << endl; - } - } - else - { - std::istringstream stream(dataString); - string setName; - stream >> setName; - DataMap::iterator itr = _dataSets.find(setName); - if (itr != _dataSets.end()) - { - shared_ptr<GraphDataBase> gdata = itr->second; - string decl; - // Hack: scan from the beginning of dataString again - if (findTaggedValue(dataString, "%Title:", decl)) - { - gdata->title = decl; - } - else if (findTaggedValue(dataString, "%XAxisTitle:", decl)) - { - gdata->xAxisText = decl; - } - else if (findTaggedValue(dataString, "%YAxisTitle:", decl)) - { - gdata->yAxisText = decl; - } - else if ((found = find_first(dataString, "%YMax:"))) - { - double ymax; - std::istringstream - stream(Glib::ustring(found.end(), dataString.end())); - stream >> ymax; - gdata->scale = ymax; - } - else + } + _buffer.append(buf, bytes_read); + string::size_type ret = string::npos; + while ((ret = _buffer.find(_lineEndChar)) != string::npos) + { + Glib::ustring dataString(_buffer, 0, ret); + // %DataSet and %CSV declare a data set; all other + // statements begin with the name of a data set. + // Except %LineEnd :) + sub_range<Glib::ustring> found; + if (dataString[0] == '%') + { + if ((found = find_first(dataString, "%DataSet:"))) + { + string setName; + int hexColor; + double scale; + string style; + istringstream stream(Glib::ustring(found.end(), + dataString.end())); + stream >> setName >> scale >> std::hex >> hexColor + >> style; + if (style == "bar" || style == "dot") + { + std::tr1::shared_ptr<GraphData<double> > + dataSet(new GraphData<double>); + dataSet->name = setName; + if (style == "dot") + dataSet->style = &GraphStyleDot::instance; + dataSet->color[0] = (hexColor >> 16) / 255.0; + dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; + dataSet->color[2] = (hexColor & 0xff) / 255.0; + dataSet->scale = scale; + _dataSets.insert(std::make_pair(setName, dataSet)); + getGraphData().push_back(dataSet); + graphDataSignal().emit(); + } + else if (style == "discreet") { - if (!_csv.elements.empty()) + std::tr1::shared_ptr<GraphData<string> > + dataSet(new GraphData<string>); + dataSet->name = setName; + dataSet->style = &GraphStyleEvent::instance; + dataSet->color[0] = (hexColor >> 16) / 255.0; + dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; + dataSet->color[2] = (hexColor & 0xff) / 255.0; + dataSet->scale = scale; + _dataSets.insert(std::make_pair(setName, dataSet)); + getGraphData().push_back(dataSet); + graphDataSignal().emit(); + } + } + else if ((found = find_first(dataString, "%CSV:"))) + { + vector<string> tokens + = commaSplit(sub_range<Glib::ustring>(found.end(), + dataString.end())); + for (vector<string>::iterator tokIter = tokens.begin(), + e = tokens.end(); + tokIter != e; + ++tokIter) + { + DataMap::iterator setIter = _dataSets.find(*tokIter); + if (setIter != _dataSets.end()) + _csv.elements + .push_back(CSVData::Element(*tokIter, + setIter->second)); + } + } + else if ((found = find_first(dataString, "%LineEnd:"))) + { + istringstream stream(Glib::ustring(found.end(), + dataString.end())); + int charAsInt = 0; + // parse hex and octal numbers too + stream >> std::setbase(0) >> charAsInt; + _lineEndChar = static_cast<char>(charAsInt); + } + else + { + cerr << "Unknown declaration " << dataString << endl; + } + } + else + { + std::istringstream stream(dataString); + string setName; + stream >> setName; + DataMap::iterator itr = _dataSets.find(setName); + if (itr != _dataSets.end()) + { + shared_ptr<GraphDataBase> gdata = itr->second; + string decl; + // Hack: scan from the beginning of dataString again + if (findTaggedValue(dataString, "%Title:", decl)) + { + gdata->title = decl; + } + else if (findTaggedValue(dataString, "%XAxisTitle:", decl)) + { + gdata->xAxisText = decl; + } + else if (findTaggedValue(dataString, "%YAxisTitle:", decl)) + { + gdata->yAxisText = decl; + } + else if ((found = find_first(dataString, "%YMax:"))) + { + double ymax; + std::istringstream + stream(Glib::ustring(found.end(), dataString.end())); + stream >> ymax; + gdata->scale = ymax; + } + else + { + if (!_csv.elements.empty()) { - vector<string> tokens = commaSplit(dataString); - int i = 0; - int64_t time; - vector<string>::iterator tokIter = tokens.begin(); - std::istringstream timeStream(*tokIter++); - timeStream >> time; - for (vector<string>::iterator e = tokens.end(); - tokIter != e; - ++tokIter, ++i) + vector<string> tokens = commaSplit(dataString); + int i = 0; + int64_t time; + vector<string>::iterator tokIter = tokens.begin(); + std::istringstream timeStream(*tokIter++); + timeStream >> time; + for (vector<string>::iterator e = tokens.end(); + tokIter != e; + ++tokIter, ++i) { - parseData(_csv.elements[i].second, time, - *tokIter); + parseData(_csv.elements[i].second, time, + *tokIter); } } - else + else { - int64_t time; - stringbuf data; - stream >> time; - stream.get(data, _lineEndChar); - parseData(itr->second, time, data.str()); + int64_t time; + stringbuf data; + stream >> time; + stream.get(data, _lineEndChar); + parseData(itr->second, time, data.str()); } } - } - } - _buffer.erase(0, ret + 1); - } - return true; - } + } + } + _buffer.erase(0, ret + 1); + } + return true; + } bool StapParser::errIoCallback(Glib::IOCondition ioCondition) { @@ -255,4 +265,18 @@ vector<string> commaSplit(const boost::sub_range<Glib::ustring>& range) ; return true; } + + void StapParser::initIo(int inFd, int errFd) + { + _inFd = inFd; + _errFd = errFd; + _ioConnection = Glib::signal_io() + .connect(sigc::mem_fun(*this, &StapParser::errIoCallback), + _errFd, + Glib::IO_IN); + _errIoConnection = Glib::signal_io() + .connect(sigc::mem_fun(*this, &StapParser::ioCallback), + _inFd, + Glib::IO_IN | Glib::IO_HUP); + } } diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx index cfb807a8..4dd711e6 100644 --- a/grapher/StapParser.hxx +++ b/grapher/StapParser.hxx @@ -38,6 +38,8 @@ namespace systemtap int _inFd; unsigned char _lineEndChar; std::tr1::shared_ptr<StapProcess> _process; + sigc::connection _ioConnection; + sigc::connection _errIoConnection; public: StapParser() : _errFd(-1), _inFd(-1), _lineEndChar('\n') @@ -63,7 +65,13 @@ namespace systemtap { _process = process; } + void initIo(int inFd, int errFd); }; sigc::signal<void, pid_t>& childDiedSignal(); + + typedef std::vector<std::tr1::shared_ptr<StapParser> > ParserList; + extern ParserList parsers; + + sigc::signal<void>& parserListChangedSignal(); } diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index 2a9a617b..00670fe0 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -106,14 +106,14 @@ private: class StapLauncher : public ChildDeathReader { public: - StapLauncher() : _argv(0), _childPid(-1), _deathCallback(0) {} + StapLauncher() : _argv(0), _childPid(-1) {} StapLauncher(char** argv) - : _argv(argv), _childPid(-1), _deathCallback(0) + : _argv(argv), _childPid(-1) { } StapLauncher(const string& stapArgs, const string& script, const string& scriptArgs) - : _childPid(-1), _deathCallback(0), _win(0), _widget(0) + : _childPid(-1), _win(0), _widget(0) { setArgs(stapArgs, script, scriptArgs); } @@ -149,10 +149,7 @@ public: _script.clear(); _scriptArgs.clear(); } - void setDeathCallback(ChildDeathReader::Callback* callback) - { - _deathCallback = callback; - } + void setWinParams(Gtk::Window* win, GraphWidget* widget) { _win = win; @@ -163,7 +160,8 @@ public: shared_ptr<StapParser> makeStapParser() { shared_ptr<StapParser> result(new StapParser); - _parsers.push_back(result); + parsers.push_back(result); + parserListChangedSignal().emit(); return result; } private: @@ -184,14 +182,22 @@ public: if (pid < 0) return pid; ParserList::iterator itr - = find_if(_parsers.begin(), _parsers.end(), pidPred(pid)); - if (itr != _parsers.end()) - (*itr)->setProcess(tr1::shared_ptr<StapProcess>()); + = find_if(parsers.begin(), parsers.end(), pidPred(pid)); + if (itr != parsers.end()) + { + tr1::shared_ptr<StapProcess> sp = (*itr)->getProcess(); + if (sp) + { + sp->pid = -1; + parserListChangedSignal().emit(); + } + } + childDiedSignal().emit(pid); return pid; } void killAll() { - for (ParserList::iterator itr = _parsers.begin(), end = _parsers.end(); + for (ParserList::iterator itr = parsers.begin(), end = parsers.end(); itr != end; ++itr) { @@ -199,15 +205,12 @@ public: kill((*itr)->getPid(), SIGTERM); } } - typedef vector<shared_ptr<StapParser> > ParserList; - ParserList _parsers; protected: char** _argv; string _stapArgs; string _script; string _scriptArgs; int _childPid; - ChildDeathReader::Callback* _deathCallback; Gtk::Window* _win; GraphWidget* _widget; }; @@ -287,17 +290,9 @@ int StapLauncher::launch() proc->scriptArgs = _scriptArgs; } sp->setProcess(proc); - _parsers.push_back(sp); - sp->setErrFd(pipefd[2]); - sp->setInFd(pipefd[0]); - Glib::signal_io().connect(sigc::mem_fun(sp.get(), - &StapParser::errIoCallback), - pipefd[2], - Glib::IO_IN); - Glib::signal_io().connect(sigc::mem_fun(sp.get(), - &StapParser::ioCallback), - pipefd[0], - Glib::IO_IN | Glib::IO_HUP); + parsers.push_back(sp); + parserListChangedSignal().emit(); + sp->initIo(pipefd[0], pipefd[2]); return childPid; } @@ -313,7 +308,7 @@ void StapLauncher::cleanUp() char buf; while (read(signalPipe[0], &buf, 1) > 0) reap(); - for (ParserList::iterator itr = _parsers.begin(), end = _parsers.end(); + for (ParserList::iterator itr = parsers.begin(), end = parsers.end(); itr != end; ++itr) { @@ -331,8 +326,10 @@ void StapLauncher::cleanUp() std::cerr << "wait: killed Pid " << killedPid << " != child Pid " << childPid << "\n"; } - else if (_deathCallback) - _deathCallback->childDied(childPid); + else + { + childDiedSignal().emit(childPid); + } } } @@ -356,13 +353,16 @@ class ProcModelColumns : public Gtk::TreeModelColumnRecord public: ProcModelColumns() { + add(_iconName); add(_scriptName); add(_proc); } + Gtk::TreeModelColumn<Glib::ustring> _iconName; Gtk::TreeModelColumn<Glib::ustring> _scriptName; Gtk::TreeModelColumn<shared_ptr<StapProcess> > _proc; }; +// This should probably be a Gtk window, with the appropriate glade magic class ProcWindow { public: @@ -372,10 +372,20 @@ public: Gtk::Window* _window; Gtk::TreeView* _dataTreeView; Glib::RefPtr<Gtk::ListStore> _listStore; + Glib::RefPtr<Gtk::TreeSelection> _listSelection; void onClose(); + void show(); + void hide(); + void onParserListChanged(); + void onSelectionChanged(); + void onKill(); +private: + bool _open; + void refresh(); }; ProcWindow::ProcWindow() + : _open(false) { try { @@ -390,12 +400,27 @@ ProcWindow::ProcWindow() throw; } _listStore = Gtk::ListStore::create(_modelColumns); - _dataTreeView->set_model(_listStore); + _dataTreeView->set_model(_listStore); + // Display a nice icon for the state of the process + Gtk::CellRendererPixbuf* cell = Gtk::manage(new Gtk::CellRendererPixbuf); + _dataTreeView->append_column("State", *cell); + Gtk::TreeViewColumn* column = _dataTreeView->get_column(0); + if (column) + column->add_attribute(cell->property_icon_name(), _modelColumns._iconName); _dataTreeView->append_column("Script", _modelColumns._scriptName); Gtk::Button* button = 0; _xml->get_widget("button5", button); button->signal_clicked().connect(sigc::mem_fun(*this, &ProcWindow::onClose), false); + _xml->get_widget("button1", button); + button->signal_clicked().connect(sigc::mem_fun(*this, &ProcWindow::onKill), + false); + parserListChangedSignal() + .connect(sigc::mem_fun(*this, &ProcWindow::onParserListChanged)); + _listSelection = _dataTreeView->get_selection(); + _listSelection->signal_changed() + .connect(sigc::mem_fun(*this, &ProcWindow::onSelectionChanged)); + } void ProcWindow::onClose() @@ -403,6 +428,63 @@ void ProcWindow::onClose() _window->hide(); } +void ProcWindow::show() +{ + _open = true; + refresh(); + _window->show(); + +} + +void ProcWindow::hide() +{ + _open = false; + _window->hide(); +} + +void ProcWindow::refresh() +{ + _listStore->clear(); + for (ParserList::iterator spitr = parsers.begin(), end = parsers.end(); + spitr != end; + ++spitr) + { + shared_ptr<StapProcess> sp = (*spitr)->getProcess(); + if (sp) + { + Gtk::TreeModel::iterator litr = _listStore->append(); + Gtk::TreeModel::Row row = *litr; + row[_modelColumns._iconName] = sp->pid >= 0 ? "gtk-yes" : "gtk-no"; + row[_modelColumns._scriptName] = sp->script; + row[_modelColumns._proc] = sp; + } + } +} + +void ProcWindow::onParserListChanged() +{ + if (_open) + { + refresh(); + _window->queue_draw(); + } +} + +void ProcWindow::onSelectionChanged() +{ +} + +void ProcWindow::onKill() +{ + Gtk::TreeModel::iterator itr = _listSelection->get_selected(); + if (!itr) + return; + Gtk::TreeModel::Row row = *itr; + shared_ptr<StapProcess> proc = row[_modelColumns._proc]; + if (proc->pid >= 0) + kill(proc->pid, SIGTERM); +} + class GrapherWindow : public Gtk::Window, public ChildDeathReader::Callback { public: @@ -411,7 +493,6 @@ public: Gtk::VBox m_Box; Gtk::ScrolledWindow scrolled; GraphWidget w; - void childDied(int pid); void setGraphicalLauncher(GraphicalStapLauncher* launcher) { _graphicalLauncher = launcher; @@ -505,30 +586,9 @@ void GrapherWindow::on_menu_script_start() void GrapherWindow::on_menu_proc_window() { - _procWindow->_listStore->clear(); - for (StapLauncher::ParserList::iterator spitr - = _graphicalLauncher->_parsers.begin(), - end = _graphicalLauncher->_parsers.end(); - spitr != end; - ++spitr) - { - shared_ptr<StapProcess> sp = (*spitr)->getProcess(); - Gtk::TreeModel::iterator litr = _procWindow->_listStore->append(); - Gtk::TreeModel::Row row = *litr; - if (sp) - row[_procWindow->_modelColumns._scriptName] = sp->script; - } - _procWindow->_window->show(); + _procWindow->show(); } -void GrapherWindow::childDied(int pid) -{ - hide(); -} - - - - int main(int argc, char** argv) { Gtk::Main app(argc, argv); @@ -553,7 +613,6 @@ int main(int argc, char** argv) else if (argc > 1) { launcher.setArgv(argv + 1); - launcher.setDeathCallback(&win); launcher.launch(); } Gtk::Main::run(win); diff --git a/grapher/processwindow.glade b/grapher/processwindow.glade index ad1bdd14..3886cb34 100644 --- a/grapher/processwindow.glade +++ b/grapher/processwindow.glade @@ -263,23 +263,60 @@ <property name="spacing">0</property> <child> - <widget class="GtkLabel" id="label1"> - <property name="height_request">17</property> + <widget class="GtkHBox" id="hbox5"> <property name="visible">True</property> - <property name="label" translatable="yes">label1</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="label" translatable="yes">stap arguments: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label7"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> </widget> <packing> <property name="padding">0</property> @@ -289,6 +326,69 @@ </child> <child> + <widget class="GtkHBox" id="hbox6"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="label" translatable="yes">script arguments: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label8"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> <widget class="GtkScrolledWindow" id="scrolledwindow2"> <property name="visible">True</property> <property name="can_focus">True</property> |