add image viewer dialog for write_dump image output, help can open link to manual

This commit is contained in:
Axel Kohlmeyer
2023-07-30 19:23:42 -04:00
parent 1c8b9e9467
commit c95bf2c14b
11 changed files with 373 additions and 25 deletions

View File

@ -66,6 +66,8 @@ set(PROJECT_SOURCES
codeeditor.h codeeditor.h
highlighter.cpp highlighter.cpp
highlighter.h highlighter.h
imageviewer.cpp
imageviewer.h
linenumberarea.h linenumberarea.h
lammpsgui.cpp lammpsgui.cpp
lammpsgui.h lammpsgui.h

View File

@ -3,13 +3,14 @@ LAMMPS-GUI TODO list:
# Short term goals # Short term goals
- add "Help" entry to menu bar. Should open a popup window with a one page description of how to use it. Use HTML or Markdown text. - add "Help" entry to menu bar. Should open a popup window with a one page description of how to use it. Use HTML or Markdown text.
- display current working directory
- add CTRL-q hotkey to log windows so you can exit the entire application (add do you really want to? dialog to this) - add CTRL-q hotkey to log windows so you can exit the entire application (add do you really want to? dialog to this)
- add "render" dialog where a "write_dump image" can be triggered. dialog should offer options for size, zoom, rotation, colors(?)
- add "syntax check" with enabled "-skiprun" flag - add "syntax check" with enabled "-skiprun" flag
- add settings dialog where certain properties can be set through customizing the LAMMPS command line - add settings dialog where certain properties can be set through customizing the LAMMPS command line
+ enable/disable OpenMP (via suffix), select number of OpenMP threads + enable/disable OpenMP (via suffix), OPT package, select number of OpenMP threads
+ toggle whether captured screen output should include input file echo + toggle whether captured screen output should include input file echo
+ select Font + select Font
+ snapshot image options
- store settings/preferences when changed and read at startup - store settings/preferences when changed and read at startup
- add list of 5(?) most recently opened/saved files to file dialog (and also write to settings state on exit) (note: must store full path!) - add list of 5(?) most recently opened/saved files to file dialog (and also write to settings state on exit) (note: must store full path!)
@ -18,4 +19,3 @@ LAMMPS-GUI TODO list:
- have command text input file in/above status bar where individual commands can be tested. have insert button to copy line into file at the current point - have command text input file in/above status bar where individual commands can be tested. have insert button to copy line into file at the current point
- support text completion as done with lammps-shell - support text completion as done with lammps-shell
- have context menu for known commands to offer retrieving help by dispatching URL to webbrowser (process index from sphinx for that purpose) - have context menu for known commands to offer retrieving help by dispatching URL to webbrowser (process index from sphinx for that purpose)
(embed html viewer to render pages locally, mathjax??)

View File

@ -12,8 +12,8 @@
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
#include "codeeditor.h" #include "codeeditor.h"
#include "linenumberarea.h"
#include "lammpsgui.h" #include "lammpsgui.h"
#include "linenumberarea.h"
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include <QDropEvent> #include <QDropEvent>
@ -84,7 +84,8 @@ void CodeEditor::dropEvent(QDropEvent *event)
event->accept(); event->accept();
fprintf(stderr, "Drag - Drop for text block not yet implemented: text=%s\n", fprintf(stderr, "Drag - Drop for text block not yet implemented: text=%s\n",
event->mimeData()->text().toStdString().c_str()); event->mimeData()->text().toStdString().c_str());
} else event->ignore(); } else
event->ignore();
} }
void CodeEditor::resizeEvent(QResizeEvent *e) void CodeEditor::resizeEvent(QResizeEvent *e)

View File

@ -0,0 +1,180 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
LAMMPS development team: developers@lammps.org
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include "imageviewer.h"
#include <QAction>
#include <QDialogButtonBox>
#include <QDir>
#include <QFileDialog>
#include <QGuiApplication>
#include <QImage>
#include <QImageReader>
#include <QLabel>
#include <QMenuBar>
#include <QMessageBox>
#include <QPalette>
#include <QScreen>
#include <QScrollArea>
#include <QScrollBar>
#include <QStatusBar>
#include <QVBoxLayout>
ImageViewer::ImageViewer(const QString &fileName, QWidget *parent) :
QDialog(parent), imageLabel(new QLabel), scrollArea(new QScrollArea), menuBar(new QMenuBar)
{
imageLabel->setBackgroundRole(QPalette::Base);
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
imageLabel->setScaledContents(true);
imageLabel->minimumSizeHint();
scrollArea->setBackgroundRole(QPalette::Dark);
scrollArea->setWidget(imageLabel);
scrollArea->setVisible(false);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(menuBar);
mainLayout->addWidget(scrollArea);
mainLayout->addWidget(buttonBox);
setWindowTitle(QString("Image Viewer: ") + QFileInfo(fileName).completeBaseName());
createActions();
QImageReader reader(fileName);
reader.setAutoTransform(true);
const QImage newImage = reader.read();
if (newImage.isNull()) {
QMessageBox::warning(this, QGuiApplication::applicationDisplayName(),
tr("Cannot load %1: %2").arg(fileName, reader.errorString()));
return;
}
image = newImage;
imageLabel->setPixmap(QPixmap::fromImage(image));
scaleFactor = 1.0;
resize(image.width() + 20, image.height() + 50);
scrollArea->setVisible(true);
fitToWindowAct->setEnabled(true);
updateActions();
if (!fitToWindowAct->isChecked()) imageLabel->adjustSize();
setLayout(mainLayout);
}
void ImageViewer::saveAs()
{
QString fileName = QFileDialog::getSaveFileName(this, "Save Image File As", QString(),
"Image Files (*.jpg *.png *.bmp *.ppm)");
saveFile(fileName);
}
void ImageViewer::copy() {}
void ImageViewer::zoomIn()
{
scaleImage(1.25);
}
void ImageViewer::zoomOut()
{
scaleImage(0.8);
}
void ImageViewer::normalSize()
{
imageLabel->adjustSize();
scaleFactor = 1.0;
}
void ImageViewer::fitToWindow()
{
bool fitToWindow = fitToWindowAct->isChecked();
scrollArea->setWidgetResizable(fitToWindow);
if (!fitToWindow) normalSize();
updateActions();
}
void ImageViewer::saveFile(const QString &fileName)
{
if (!fileName.isEmpty()) image.save(fileName);
}
void ImageViewer::createActions()
{
QMenu *fileMenu = menuBar->addMenu(tr("&File"));
saveAsAct = fileMenu->addAction(tr("&Save As..."), this, &ImageViewer::saveAs);
saveAsAct->setEnabled(false);
fileMenu->addSeparator();
copyAct = fileMenu->addAction(tr("&Copy"), this, &ImageViewer::copy);
copyAct->setShortcut(QKeySequence::Copy);
copyAct->setEnabled(false);
fileMenu->addSeparator();
QAction *exitAct = fileMenu->addAction(tr("&Close"), this, &QWidget::close);
exitAct->setShortcut(tr("Ctrl+W"));
QMenu *viewMenu = menuBar->addMenu(tr("&View"));
zoomInAct = viewMenu->addAction(tr("Zoom &In (25%)"), this, &ImageViewer::zoomIn);
zoomInAct->setShortcut(QKeySequence::ZoomIn);
zoomInAct->setEnabled(false);
zoomOutAct = viewMenu->addAction(tr("Zoom &Out (25%)"), this, &ImageViewer::zoomOut);
zoomOutAct->setShortcut(QKeySequence::ZoomOut);
zoomOutAct->setEnabled(false);
normalSizeAct = viewMenu->addAction(tr("&Normal Size"), this, &ImageViewer::normalSize);
normalSizeAct->setShortcut(tr("Ctrl+S"));
normalSizeAct->setEnabled(false);
viewMenu->addSeparator();
fitToWindowAct = viewMenu->addAction(tr("&Fit to Window"), this, &ImageViewer::fitToWindow);
fitToWindowAct->setEnabled(false);
fitToWindowAct->setCheckable(true);
fitToWindowAct->setShortcut(tr("Ctrl+F"));
}
void ImageViewer::updateActions()
{
saveAsAct->setEnabled(!image.isNull());
copyAct->setEnabled(!image.isNull());
zoomInAct->setEnabled(!fitToWindowAct->isChecked());
zoomOutAct->setEnabled(!fitToWindowAct->isChecked());
normalSizeAct->setEnabled(!fitToWindowAct->isChecked());
}
void ImageViewer::scaleImage(double factor)
{
scaleFactor *= factor;
imageLabel->resize(scaleFactor * imageLabel->pixmap(Qt::ReturnByValue).size());
adjustScrollBar(scrollArea->horizontalScrollBar(), factor);
adjustScrollBar(scrollArea->verticalScrollBar(), factor);
zoomInAct->setEnabled(scaleFactor < 3.0);
zoomOutAct->setEnabled(scaleFactor > 0.333);
}
void ImageViewer::adjustScrollBar(QScrollBar *scrollBar, double factor)
{
scrollBar->setValue(
int(factor * scrollBar->value() + ((factor - 1) * scrollBar->pageStep() / 2)));
}
// Local Variables:
// c-basic-offset: 4
// End:

View File

@ -0,0 +1,64 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
LAMMPS development team: developers@lammps.org
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#ifndef IMAGEVIEWER_H
#define IMAGEVIEWER_H
#include <QDialog>
#include <QImage>
class QAction;
class QMenuBar;
class QDialogButtonBox;
class QLabel;
class QScrollArea;
class QScrollBar;
class QStatusBar;
class ImageViewer : public QDialog {
Q_OBJECT
public:
explicit ImageViewer(const QString &fileName, QWidget *parent = nullptr);
private slots:
void saveAs();
void copy();
void zoomIn();
void zoomOut();
void normalSize();
void fitToWindow();
private:
void createActions();
void updateActions();
void saveFile(const QString &fileName);
void scaleImage(double factor);
void adjustScrollBar(QScrollBar *scrollBar, double factor);
private:
QImage image;
QMenuBar *menuBar;
QLabel *imageLabel;
QScrollArea *scrollArea;
QDialogButtonBox *buttonBox;
double scaleFactor = 1.0;
QAction *saveAsAct;
QAction *copyAct;
QAction *zoomInAct;
QAction *zoomOutAct;
QAction *normalSizeAct;
QAction *fitToWindowAct;
};
#endif

View File

@ -14,6 +14,7 @@
#include "lammpsgui.h" #include "lammpsgui.h"
#include "highlighter.h" #include "highlighter.h"
#include "imageviewer.h"
#include "lammpsrunner.h" #include "lammpsrunner.h"
#include "preferences.h" #include "preferences.h"
#include "stdcapture.h" #include "stdcapture.h"
@ -30,6 +31,9 @@
#include <QStatusBar> #include <QStatusBar>
#include <QTextStream> #include <QTextStream>
#include <QTimer> #include <QTimer>
#include <QDesktopServices>
#include <QUrl>
#include <cstring> #include <cstring>
#include <string> #include <string>
@ -44,6 +48,12 @@
#include <omp.h> #include <omp.h>
#endif #endif
#if defined(_WIN32)
#include <io.h>
#else
#include <unistd.h>
#endif
// duplicate string // duplicate string
static char *mystrdup(const std::string &text) static char *mystrdup(const std::string &text)
{ {
@ -54,9 +64,9 @@ static char *mystrdup(const std::string &text)
LammpsGui::LammpsGui(QWidget *parent, const char *filename) : LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
QMainWindow(parent), ui(new Ui::LammpsGui), highlighter(nullptr), capturer(nullptr), QMainWindow(parent), ui(new Ui::LammpsGui), highlighter(nullptr), capturer(nullptr),
status(nullptr), logwindow(nullptr), logupdater(nullptr), progress(nullptr), status(nullptr), logwindow(nullptr), imagewindow(nullptr), logupdater(nullptr),
prefdialog(nullptr), lammps_handle(nullptr), plugin_handle(nullptr), plugin_path(nullptr), progress(nullptr), prefdialog(nullptr), lammps_handle(nullptr), plugin_handle(nullptr),
is_running(false) plugin_path(nullptr), is_running(false)
{ {
ui->setupUi(this); ui->setupUi(this);
this->setCentralWidget(ui->textEdit); this->setCentralWidget(ui->textEdit);
@ -78,6 +88,17 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
#endif #endif
#endif #endif
const char *tmpdir = getenv("TMPDIR");
if (!tmpdir) tmpdir = getenv("TMP");
if (!tmpdir) tmpdir = getenv("TEMPDIR");
if (!tmpdir) tmpdir = getenv("TEMP");
#if _WIN32
if (!tmpdir) tmpdir = "C:\\Windows\\Temp";
#else
if (!tmpdir) tmpdir = "/tmp";
#endif
temp_dir = tmpdir;
lammps_args.clear(); lammps_args.clear();
lammps_args.push_back(mystrdup("LAMMPS-GUI")); lammps_args.push_back(mystrdup("LAMMPS-GUI"));
lammps_args.push_back(mystrdup("-log")); lammps_args.push_back(mystrdup("-log"));
@ -107,8 +128,10 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
connect(ui->actionRedo, &QAction::triggered, this, &LammpsGui::redo); connect(ui->actionRedo, &QAction::triggered, this, &LammpsGui::redo);
connect(ui->actionRun_Buffer, &QAction::triggered, this, &LammpsGui::run_buffer); connect(ui->actionRun_Buffer, &QAction::triggered, this, &LammpsGui::run_buffer);
connect(ui->actionStop_LAMMPS, &QAction::triggered, this, &LammpsGui::stop_run); connect(ui->actionStop_LAMMPS, &QAction::triggered, this, &LammpsGui::stop_run);
connect(ui->actionImage, &QAction::triggered, this, &LammpsGui::view_image);
connect(ui->actionAbout_LAMMPS_GUI, &QAction::triggered, this, &LammpsGui::about); connect(ui->actionAbout_LAMMPS_GUI, &QAction::triggered, this, &LammpsGui::about);
connect(ui->action_Help, &QAction::triggered, this, &LammpsGui::help); connect(ui->action_Help, &QAction::triggered, this, &LammpsGui::help);
connect(ui->actionLAMMPS_Manual, &QAction::triggered, this, &LammpsGui::manual);
connect(ui->actionEdit_Preferences, &QAction::triggered, this, &LammpsGui::preferences); connect(ui->actionEdit_Preferences, &QAction::triggered, this, &LammpsGui::preferences);
connect(ui->textEdit->document(), &QTextDocument::modificationChanged, this, connect(ui->textEdit->document(), &QTextDocument::modificationChanged, this,
&LammpsGui::modified); &LammpsGui::modified);
@ -158,6 +181,7 @@ LammpsGui::~LammpsGui()
delete capturer; delete capturer;
delete status; delete status;
delete logwindow; delete logwindow;
delete imagewindow;
} }
void LammpsGui::new_document() void LammpsGui::new_document()
@ -469,6 +493,55 @@ void LammpsGui::run_buffer()
logupdater->start(1000); logupdater->start(1000);
} }
void LammpsGui::view_image()
{
// LAMMPS is not re-entrant, so we can only query LAMMPS when it is not running
if (!is_running) {
start_lammps();
int box = 0;
#if defined(LAMMPS_GUI_USE_PLUGIN)
box = ((liblammpsplugin_t *)plugin_handle)->extract_setting(lammps_handle, "box_exists");
#else
box = lammps_extract_setting(lammps_handle, "box_exist");
#endif
if (!box) {
QMessageBox::warning(this, "ImageViewer Error",
"Cannot create snapshot image without a system box");
return;
}
std::string dumpcmd = "write_dump all image '";
QString dumpfile = temp_dir;
#if defined(_WIN32)
dumpfile += '\\';
#else
dumpfile += '/';
#endif
dumpfile += current_file + ".ppm";
dumpcmd += dumpfile.toStdString() + "' type type size 800 600";
#if defined(LAMMPS_GUI_USE_PLUGIN)
((liblammpsplugin_t *)plugin_handle)->command(lammps_handle, dumpcmd.c_str());
#else
lammps_command(lammps_handle, dumpcmd.c_str());
#endif
imagewindow = new ImageViewer(dumpfile);
#if 0
#if defined(_WIN32)
_unlink(dumpfile.toLocal8Bit());
#else
unlink(dumpfile.toLocal8Bit());
#endif
#endif
} else {
QMessageBox::warning(this, "ImageViewer Error",
"Cannot create snapshot image while LAMMPS is running");
return;
}
imagewindow->show();
}
void LammpsGui::clear() void LammpsGui::clear()
{ {
if (lammps_handle) { if (lammps_handle) {
@ -500,9 +573,9 @@ void LammpsGui::about()
start_lammps(); start_lammps();
capturer->BeginCapture(); capturer->BeginCapture();
#if defined(LAMMPS_GUI_USE_PLUGIN) #if defined(LAMMPS_GUI_USE_PLUGIN)
((liblammpsplugin_t *)plugin_handle)->commands_string(lammps_handle, "info config"); ((liblammpsplugin_t *)plugin_handle)->commands(lammps_handle, "info config");
#else #else
lammps_commands_string(lammps_handle, "info config"); lammps_command(lammps_handle, "info config");
#endif #endif
capturer->EndCapture(); capturer->EndCapture();
info = capturer->GetCapture(); info = capturer->GetCapture();
@ -515,7 +588,7 @@ void LammpsGui::about()
msg.setWindowTitle("About LAMMPS-GUI"); msg.setWindowTitle("About LAMMPS-GUI");
msg.setText(version.c_str()); msg.setText(version.c_str());
msg.setInformativeText(info.c_str()); msg.setInformativeText(info.c_str());
msg.setIconPixmap(QPixmap(":/lammps-icon-128x128.png").scaled(64,64)); msg.setIconPixmap(QPixmap(":/lammps-icon-128x128.png").scaled(64, 64));
msg.setStandardButtons(QMessageBox::Ok); msg.setStandardButtons(QMessageBox::Ok);
QFont font; QFont font;
font.setFixedPitch(true); font.setFixedPitch(true);
@ -532,6 +605,11 @@ void LammpsGui::help()
QMessageBox::information(this, "LAMMPS-GUI Help", helpmsg); QMessageBox::information(this, "LAMMPS-GUI Help", helpmsg);
} }
void LammpsGui::manual()
{
QDesktopServices::openUrl(QUrl("https://docs.lammps.org/"));
}
void LammpsGui::preferences() void LammpsGui::preferences()
{ {
QString helpmsg = "This is LAMMPS-GUI version " LAMMPS_GUI_VERSION; QString helpmsg = "This is LAMMPS-GUI version " LAMMPS_GUI_VERSION;

View File

@ -34,6 +34,7 @@ class QTimer;
class Highlighter; class Highlighter;
class StdCapture; class StdCapture;
class Preferences; class Preferences;
class ImageViewer;
class LammpsGui : public QMainWindow { class LammpsGui : public QMainWindow {
Q_OBJECT Q_OBJECT
@ -64,8 +65,10 @@ private slots:
void clear(); void clear();
void run_buffer(); void run_buffer();
void stop_run(); void stop_run();
void view_image();
void about(); void about();
void help(); void help();
void manual();
void logupdate(); void logupdate();
void modified(); void modified();
void preferences(); void preferences();
@ -76,12 +79,14 @@ private:
StdCapture *capturer; StdCapture *capturer;
QLabel *status; QLabel *status;
QPlainTextEdit *logwindow; QPlainTextEdit *logwindow;
ImageViewer *imagewindow;
QTimer *logupdater; QTimer *logupdater;
QProgressBar *progress; QProgressBar *progress;
Preferences *prefdialog; Preferences *prefdialog;
QString current_file; QString current_file;
QString current_dir; QString current_dir;
QString temp_dir;
void *lammps_handle; void *lammps_handle;
void *plugin_handle; void *plugin_handle;
const char *plugin_path; const char *plugin_path;

View File

@ -67,6 +67,8 @@
</property> </property>
<addaction name="actionRun_Buffer"/> <addaction name="actionRun_Buffer"/>
<addaction name="actionStop_LAMMPS"/> <addaction name="actionStop_LAMMPS"/>
<addaction name="separator"/>
<addaction name="actionImage"/>
</widget> </widget>
<widget class="QMenu" name="menuAbout"> <widget class="QMenu" name="menuAbout">
<property name="title"> <property name="title">
@ -74,6 +76,7 @@
</property> </property>
<addaction name="actionAbout_LAMMPS_GUI"/> <addaction name="actionAbout_LAMMPS_GUI"/>
<addaction name="action_Help"/> <addaction name="action_Help"/>
<addaction name="actionLAMMPS_Manual"/>
</widget> </widget>
<addaction name="menuFile"/> <addaction name="menuFile"/>
<addaction name="menuEdit"/> <addaction name="menuEdit"/>
@ -276,6 +279,20 @@
<string>Ctrl+/</string> <string>Ctrl+/</string>
</property> </property>
</action> </action>
<action name="actionImage">
<property name="icon">
<iconset theme="emblem-photos"/>
</property>
<property name="text">
<string>&amp;View Snapshot</string>
</property>
<property name="toolTip">
<string>View Snapshot of current LAMMPS state</string>
</property>
<property name="shortcut">
<string>Ctrl+I</string>
</property>
</action>
<action name="actionAbout_LAMMPS_GUI"> <action name="actionAbout_LAMMPS_GUI">
<property name="icon"> <property name="icon">
<iconset theme="help-about"> <iconset theme="help-about">
@ -306,7 +323,15 @@
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>Edit Preferences...</string> <string>Edit &amp;Preferences...</string>
</property>
</action>
<action name="actionLAMMPS_Manual">
<property name="icon">
<iconset theme="help-browser"/>
</property>
<property name="text">
<string>LAMMPS &amp;Manual</string>
</property> </property>
</action> </action>
</widget> </widget>

View File

@ -13,13 +13,7 @@
#include "preferences.h" #include "preferences.h"
#include <QTabWidget>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QTabWidget>
Preferences::Preferences(QWidget *parent) : QDialog(parent) Preferences::Preferences(QWidget *parent) : QDialog(parent) {}
{
}

View File

@ -19,8 +19,7 @@
class QTabWidget; class QTabWidget;
class QDialogButtonBox; class QDialogButtonBox;
class Preferences : public QDialog class Preferences : public QDialog {
{
Q_OBJECT Q_OBJECT
public: public:

View File

@ -46,7 +46,7 @@ StdCapture::StdCapture() : m_oldStdOut(0), m_capturing(false)
if (_pipe(m_pipe, 65536, O_BINARY) == -1) return; if (_pipe(m_pipe, 65536, O_BINARY) == -1) return;
#else #else
if (pipe(m_pipe) == -1) return; if (pipe(m_pipe) == -1) return;
fcntl(m_pipe[READ], F_SETFL, fcntl(m_pipe[READ], F_GETFL)|O_NONBLOCK); fcntl(m_pipe[READ], F_SETFL, fcntl(m_pipe[READ], F_GETFL) | O_NONBLOCK);
#endif #endif
m_oldStdOut = dup(fileno(stdout)); m_oldStdOut = dup(fileno(stdout));
if (m_oldStdOut == -1) return; if (m_oldStdOut == -1) return;