From 6ec6be1a41fcad3d222adba2c1bb4e2b5d342420 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Mon, 15 Jan 2018 19:54:52 +0100 Subject: [PATCH] add working termwindow class CTermWindow() should be usable as drop-in replacement for CShellWindow() Origin commit data ------------------ Commit: https://github.com/neutrino-images/ni-neutrino/commit/bccd54778122afae56ec0ab73296154b461de58d Author: Stefan Seyfried Date: 2018-01-15 (Mon, 15 Jan 2018) --- src/Makefile.am | 1 + src/gui/widget/Makefile.am | 1 + src/gui/widget/termwindow.cpp | 133 ++++++++++++++++++++++++++++++++++ src/gui/widget/termwindow.h | 94 ++++++++++++++++++++++++ 4 files changed, 229 insertions(+) create mode 100644 src/gui/widget/termwindow.cpp create mode 100644 src/gui/widget/termwindow.h diff --git a/src/Makefile.am b/src/Makefile.am index 558778453..e120653fe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -112,6 +112,7 @@ neutrino_LDADD = \ $(top_builddir)/lib/libtuxtxt/libtuxtxt.a \ $(top_builddir)/lib/libdvbsub/libdvbsub.a \ $(top_builddir)/lib/libiw/libiw.a \ + $(top_builddir)/src/gui/widget/yaft/libneutrino_gui_terminal.a \ @CURL_LIBS@ \ @FREETYPE_LIBS@ \ @PNG_LIBS@ \ diff --git a/src/gui/widget/Makefile.am b/src/gui/widget/Makefile.am index f55b98e45..3c0e896c9 100644 --- a/src/gui/widget/Makefile.am +++ b/src/gui/widget/Makefile.am @@ -34,6 +34,7 @@ libneutrino_gui_widget_a_SOURCES = \ shellwindow.cpp \ stringinput.cpp \ stringinput_ext.cpp \ + termwindow.cpp \ textbox.cpp libneutrino_gui_widget2_a_SOURCES = \ diff --git a/src/gui/widget/termwindow.cpp b/src/gui/widget/termwindow.cpp new file mode 100644 index 000000000..dda63af23 --- /dev/null +++ b/src/gui/widget/termwindow.cpp @@ -0,0 +1,133 @@ +/* + * Terminal window class + * + * (C) 2017,2017 Stefan Seyfried + * SPDX-License-Identifier: GPL-2.0 + * + * drop-in-replacement for CShellWindow() + * loosely based on shellwindow.cpp, heavily stripped down. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "termwindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CTermWindow::CTermWindow(const std::string &Command, const int Mode, int *Res, bool auto_exec) +{ + fprintf(stderr, "%s:%d mode %d\n", __func__, __LINE__, Mode); + frameBuffer = CFrameBuffer::getInstance(); + + setCommand(Command, Mode, Res, auto_exec); +} + +void CTermWindow::setCommand(const std::string &Command, const int Mode, int* Res, bool auto_exec) +{ + command = Command; + mode = Mode; + fprintf(stderr, "%s:%d mode %d\n", __func__, __LINE__, mode); + res = Res; + if (auto_exec) + exec(); +} + +void CTermWindow::exec() +{ + fprintf(stderr, "CTermWindow::exec: mode %d command: %s\n", mode, command.c_str()); + std::string cmd; + if (mode == 0){ /* not used */ + cmd = "PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin ; export PATH ; " + command + " 2>/dev/null >&2"; + int r = my_system(cmd.c_str()); + if (res) { + if (r == -1) + *res = r; + else + *res = WEXITSTATUS(r); + dprintf(DEBUG_NORMAL, "[CTermWindow] [%s - %d] Error! system returns: %d command: %s\n", __func__, __LINE__, *res, cmd.c_str()); + } + } + else { + const char * const argv[] = {"/bin/sh\0", "-c\0", command.c_str(), NULL }; + int ret; +fprintf(stderr, "%s:%d %s\n", __func__, __LINE__, argv[0]); + YaFT *y = new YaFT(argv, res, !!(mode & VERBOSE), OnShellOutputLoop); + ret = y->run(); + if (res) + *res = ret; + delete y; +fprintf(stderr, "%s:%d\n", __func__, __LINE__); + showResult(); + } +} + +void CTermWindow::showResult() +{ + if (mode == 0) /* not used */ + return; + + bool show_button = false; + bool exit = false; + + if (mode & ACKNOWLEDGE) + show_button = true; + else if (mode & ACKNOWLEDGE_EVENT) { + if (res && *res != 0){ + OnResultError(res); + if (OnResultError.empty()) + DisplayErrorMessage("Error while execution of task. Please see window for details!"); + show_button = true; + }else{ + OnResultOk(res); + exit = true; //TODO: evaluate plausible statement + } + } + + if (mode & VERBOSE) { + if (show_button) { + int b_width = 150; + int b_height = 35; + int xpos = frameBuffer->getScreenWidth() - b_width; + int ypos = frameBuffer->getScreenHeight() - b_height; + CComponentsButton btn(xpos, ypos, b_width, b_height, LOCALE_MESSAGEBOX_BACK, NEUTRINO_ICON_BUTTON_OKAY, NULL, true, true); + btn.setColorBody(COL_MENUCONTENT_PLUS_0); + btn.paint(false); + } + + neutrino_msg_t msg; + neutrino_msg_data_t data; + uint64_t timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU]); + + if (!exit) { + do { + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd); + } while (msg != CRCInput::RC_ok && msg != CRCInput::RC_home && msg != CRCInput::RC_timeout); + } + } + frameBuffer->Clear(); +} + +#if 0 +// only for debug +void CTermWindow::handleShellOutput(std::string* cur_line, int* Res, bool* /*ok*/) +{ + int _res = *Res; + std::string line = *cur_line; + fprintf(stderr, "%s\n", line.c_str()); + *Res = _res; +} +#endif + +CTermWindow::~CTermWindow() +{ +} diff --git a/src/gui/widget/termwindow.h b/src/gui/widget/termwindow.h new file mode 100644 index 000000000..2bb858520 --- /dev/null +++ b/src/gui/widget/termwindow.h @@ -0,0 +1,94 @@ +/* + * terminal window class + * (C) 2017,2018 Stefan Seyfried + * SPDX-License-Identifier: GPL-2.0 + * + * designed to be more or less drop-in-compatible to CShellWindow() + * derived from shellwindow.h +*/ + +#ifndef __WIDGET_SHELLWINDOW_H__ +#define __WIDGET_SHELLWINDOW_H__ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +class CFrameBuffer; +class CTermWindow : public sigc::trackable +{ + private: + int mode; + std::string command; + int* res; + CFrameBuffer *frameBuffer; + void showResult(); + void handleShellOutput(std::string* cur_line, int* Res, bool* ok); + + public: + // shell window modes for handled shell output. //NOTE: mode 0 use only system calls, with unhandled return values and no handled shell output + enum shellwindow_modes + { + /*SYSTEM = 0, */ + QUIET = 1, // no window + VERBOSE = 2, // show window + ACKNOWLEDGE = 4, // show result button inside window after execution, no message box NOTE: only in VERBOSE mode + ACKNOWLEDGE_EVENT = 8 // same like ACKNOWLEDGE but shows a default error message box or a slot handled action instead default error message box + }; + CTermWindow(const std::string &Command, const int Mode = 0, int* Res = NULL, bool auto_exec = true); + ~CTermWindow(); + void setCommand(const std::string &Command, const int Mode = 0, int* Res = NULL, bool auto_exec = true); +#if 0 + std::string getCommand(){return command;} + int getMode(){return mode;} +#endif + void exec(); + + /*! + signal/event handler runs on loop in exec method + this allows to use the shell output lines in other objects eg. for evaluation of error or status data + example for implamentation in your class: + ...your code... + //assuming in your class is declared a member function named YourMemberFunction(std::string& arg), parameter is a string as rev: + //Tis function should handle the shell output! + //declare a slot with return value as 'void' and parameter as 'string', here by rev! + sigc::slot1 sl_shell_output; + //fill the slot with your member function in your class that do evaluate the output lines + sl_shell_output = sigc::mem_fun(*this, &CYourClass::YourMemberFunction); + //create the CShellWindow object in verbose mode, important: parameter 'auto_exec' must be set to 'false', so it is possible to connect the slot before engages the exec() methode + CTermWindow shell(cmd, (verbose ? CTermWindow::VERBOSE : 0) | (acknowledge ? CTermWindow::ACKNOWLEDGE_MSG : 0), &res, false); + //connect slot + shell.OnShellOutputLoop.connect(sl_shell_output); + //now exec... + shell.exec(); + ...other code... + */ + sigc::signal OnShellOutputLoop; + /*! + signal/event handler runs after task is finished. + NOTE: works only with ACKNOWLEDGE_EVENT mode + After executed task comes a default messages (see method showResult()), but with these slots it is possible to use other messages + or any desired action without any touching this class. + Example for implementation in foreign class let show an alternate message than default message: + ...your code... + //assuming in your foreign class is declared a member function named YourMemberFunction() without return value and int* as parmeter This method should run + instead the default message. + //declare a slot with return value as 'void' and wihout any parameter + sigc::slot sl_result_err; + //fill the slot with your member function in your class with your action + sl_result_err = sigc::mem_fun(*this, &CYourClass::YourMemberFunction); + //create the CShellWindow object in verbose mode, important: parameter 'auto_exec' must be set to 'false', so it is possible to connect the slot before engages the exec() methode + CTermWindow shell(cmd, (verbose ? CTermWindow::VERBOSE : 0) | (acknowledge ? CTermWindow::ACKNOWLEDGE_MSG : 0), &res, false); + //connect slot + shell1.OnResultError.connect(sl_result_err); + //now exec... + shell.exec(); + ...other code... + Use of OnResultOk is similar with OnResultError. + */ + sigc::signal OnResultError; + sigc::signal OnResultOk; +}; + +#endif