<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	シリアルＩ／Ｏ（WIN32）
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/glfw_app/blob/master/LICENSE
*/
//=====================================================================//
#include <windows.h>
#include <string>

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	シリアル通信クラス（WIN32)
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class serial_win32 {
	public:
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief	パリティー・タイプ
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class PARITY {
			NONE,	///< パリティー無し
			EVEN,	///< 偶数パリティー
			ODD,	///< 奇数パリティー
		};

	private:
		HANDLE		fd_;

		std::string	error_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		*/
		//-----------------------------------------------------------------//
		serial_win32() : fd_(INVALID_HANDLE_VALUE) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	オープン
			@param[in]	port	ポート名
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool open(const std::string& port)
		{
			std::string full("\\\\.\\");
			full += port;
///			snprintf(port_full_name, sizeof port_full_name - 2u, "\\\\.\\%s", port);
///			if(4 <= verbose_level) {
///				printf("\t\tOpen port: %s\n", port_full_name);
///			}
			fd_ = CreateFile(full.c_str(),
					GENERIC_READ | GENERIC_WRITE,
                    0,
                    NULL,
                    OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL,
                    0);

			bool ret = false;
			if(INVALID_HANDLE_VALUE == fd_) {
				int error_num = GetLastError();
				char error_string[1024];
				FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
					NULL,
					error_num,
					MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
					error_string,
					sizeof error_string,
					NULL);
///			fprintf(stderr, "Unable to open port: (%i) %s\n", error_num, error_string);
					error_ = error_string;
			} else {
				DCB dcbSerialParams;
				GetCommState(fd_, &dcbSerialParams);
				dcbSerialParams.BaudRate = CBR_115200;
				dcbSerialParams.ByteSize = 8;
				dcbSerialParams.StopBits = ONESTOPBIT;
				dcbSerialParams.Parity   = NOPARITY;
				SetCommState(fd_, &dcbSerialParams);

				COMMTIMEOUTS timeouts;
				timeouts.ReadIntervalTimeout=50;
				timeouts.ReadTotalTimeoutConstant=50;
				timeouts.ReadTotalTimeoutMultiplier=10;
				timeouts.WriteTotalTimeoutConstant=0;
				timeouts.WriteTotalTimeoutMultiplier=0;
				SetCommTimeouts(fd_, &timeouts);
				FlushFileBuffers(fd_);
				ret = true;
			}
			return ret;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	ボーレートの設定
			@param[in]	baud	ボーレート
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool set_baud(int baud)
		{
			DCB dcbSerialParams;
			GetCommState(fd_, &dcbSerialParams);
			dcbSerialParams.BaudRate = baud;
			return SetCommState(fd_, &dcbSerialParams) != 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	パリティーの設定
			@param[in]	parity	パリティー・タイプ
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool set_parity(PARITY parity)
		{
			DCB dcbSerialParams;
			GetCommState(fd_, &dcbSerialParams);
			switch(parity) {
			case PARITY::EVEN:
				dcbSerialParams.Parity = EVENPARITY;
				break;
			case PARITY::ODD:
				dcbSerialParams.Parity = ODDPARITY;
				break;
			case PARITY::NONE:
			default:
				dcbSerialParams.Parity = NOPARITY;
				break;
			}
			return SetCommState(fd_, &dcbSerialParams) != 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	DTR の設定（Data Terminal Ready)
			@param[in]	value	設定値
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool set_dtr(bool value)
		{
			int command;
			if(value) {
				command = SETDTR;
			} else {
				command = CLRDTR;
			}
			return EscapeCommFunction(fd_, command) != 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	RTS の設定（Request To Send)
			@param[in]	value	設定値
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool set_rts(bool value)
		{
			int command;
			if(value) {
				command = SETRTS;
			} else {
				command = CLRRTS;
			}
			return EscapeCommFunction(fd_, command) != 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	TXD の設定
			@param[in]	value	設定値
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool set_txd(bool value)
		{
			int command;
			if(value) {
				command = SETBREAK;
			} else {
				command = CLRBREAK;

			}
			return EscapeCommFunction(fd_, command) != 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	フラッシュ
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool flush()
		{
//			if(4 <= verbose_level) {
//				printf("\t\tFlush IO buffers\n");
//			}
			return PurgeComm(fd_, PURGE_RXCLEAR | PURGE_TXCLEAR) != 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	ライト
			@param[in]	src	転送元
			@param[in]	len	長さ（バイト）
			@return 書き込んだサイズ
		*/
		//-----------------------------------------------------------------//
		uint32_t write(const void* src, uint32_t len)
		{
#if 0
			if(4 <= verbose_level) {
				unsigned char *p = (unsigned char*)buf;
				unsigned int i;
				printf("\t\tsend(%u): ", len);
				for(i = len; 0 < i; --i) {
					printf("%02X ", *p++);
				}
				printf("\n");
			}
#endif
			int bytes_left = len;
			DWORD bytes_written;
			const uint8_t* p = reinterpret_cast<const uint8_t*>(src);
			do {
				if(0 == WriteFile(fd_, p, bytes_left, &bytes_written, NULL)) {
//					fprintf(stderr, "Failed to write to port.\n");
					return false;
				}
				p += bytes_written;
				bytes_left -= bytes_written;
			} while(0 < bytes_left) ;
			return len - bytes_left;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	リード
			@param[out]	dst	転送先
			@param[in]	len	長さ（バイト）
			@return 書き込んだサイズ
		*/
		//-----------------------------------------------------------------//
		uint32_t read(void *dst, int len)
		{
			int bytes_left = len;
			DWORD bytes_read;
			uint8_t* p = reinterpret_cast<uint8_t*>(dst);
			do {
				if(0 == ReadFile(fd_, p, bytes_left, &bytes_read, NULL)) {
///					fprintf(stderr, "Failed to read from port.\n");
//					last_error_ = 1;
					return 0;
				}
				if(0 == bytes_read) {
					break;
				}
				p += bytes_read;
				bytes_left -= bytes_read;
			} while(0 < bytes_left) ;

			uint32_t nbytes = len - bytes_left;
#if 0
			if(4 <= verbose_level) {
				p = dst;
				unsigned int i;
				printf("\t\trecv(%u): ", nbytes);
				for(i = nbytes; 0 < i; --i) {
					printf("%02X ", *pbuf++);
				}
				printf("\n");
			}
#endif
			return nbytes;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	クローズ
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool close() {
//			if(4 <= verbose_level) {
//				printf("\t\tClose port\n");
//			}
			return CloseHandle(fd_) != 0;
		}
	};
}
<commit_msg>update port list API<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	シリアルＩ／Ｏ（WIN32）
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/glfw_app/blob/master/LICENSE
*/
//=====================================================================//
#include <windows.h>
#include <winioctl.h>
#include <setupapi.h>
#include <string>
#include <vector>

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	シリアル通信クラス（WIN32)
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class serial_win32 {
	public:
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief	シリアル・ポート名構造体
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		struct name_t {
			std::string		port;	///< ポート名
			std::string		info;	///< ポート情報
		};
		typedef std::vector<name_t> name_list;

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief	パリティー・タイプ
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class PARITY {
			NONE,	///< パリティー無し
			EVEN,	///< 偶数パリティー
			ODD,	///< 奇数パリティー
		};

	private:
		HANDLE		fd_;

		std::string	error_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		*/
		//-----------------------------------------------------------------//
		serial_win32() : fd_(INVALID_HANDLE_VALUE) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	ポート・リストを取得
			@return ポート・リスト
		*/
		//-----------------------------------------------------------------//
		name_list get_list() const
		{
			name_list list;
			// デバイス情報セットを取得
			HDEVINFO hi = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, 0, 0,
				DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
			if(hi == 0) {
				return list;
			}

			SP_DEVINFO_DATA data = { 0 };
			data.cbSize = sizeof(data);
			int idx = 0;
			while(SetupDiEnumDeviceInfo(hi, idx, &data)) {
				name_t t;
				// COM ポート名の取得
				HKEY key = SetupDiOpenDevRegKey(hi, &data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
				if(key) {
					BYTE name[256];
					DWORD type = 0;
					DWORD size = sizeof(name);
					RegQueryValueEx(key, _T("PortName"), NULL, &type, name, &size);
					t.port = reinterpret_cast<const char*>(name);
				}

				//	デバイスの情報を取得
				DWORD dt = 0;
				PBYTE ptr = nullptr;
				DWORD size = 0;
				SetupDiGetDeviceRegistryProperty(hi, &data, SPDRP_DEVICEDESC, &dt, ptr, size, &size);
				if(size > 0) {
					ptr = new BYTE[size];
					SetupDiGetDeviceRegistryProperty(hi, &data, SPDRP_DEVICEDESC, &dt, ptr, size, &size);
					t.info = reinterpret_cast<const char*>(ptr);
					delete[] ptr;
				}
				++idx;
				list.push_back(t);
			}

			// デバイス情報セットを解放
			SetupDiDestroyDeviceInfoList(hi);

			return list;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	オープン
			@param[in]	port	ポート名
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool open(const std::string& port)
		{
			std::string full("\\\\.\\");
			full += port;
///			snprintf(port_full_name, sizeof port_full_name - 2u, "\\\\.\\%s", port);
///			if(4 <= verbose_level) {
///				printf("\t\tOpen port: %s\n", port_full_name);
///			}
			fd_ = CreateFile(full.c_str(),
					GENERIC_READ | GENERIC_WRITE,
                    0,
                    NULL,
                    OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL,
                    0);

			bool ret = false;
			if(INVALID_HANDLE_VALUE == fd_) {
				int error_num = GetLastError();
				char error_string[1024];
				FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
					NULL,
					error_num,
					MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
					error_string,
					sizeof error_string,
					NULL);
///			fprintf(stderr, "Unable to open port: (%i) %s\n", error_num, error_string);
					error_ = error_string;
			} else {
				DCB dcbSerialParams;
				GetCommState(fd_, &dcbSerialParams);
				dcbSerialParams.BaudRate = CBR_115200;
				dcbSerialParams.ByteSize = 8;
				dcbSerialParams.StopBits = ONESTOPBIT;
				dcbSerialParams.Parity   = NOPARITY;
				SetCommState(fd_, &dcbSerialParams);

				COMMTIMEOUTS timeouts;
				timeouts.ReadIntervalTimeout=50;
				timeouts.ReadTotalTimeoutConstant=50;
				timeouts.ReadTotalTimeoutMultiplier=10;
				timeouts.WriteTotalTimeoutConstant=0;
				timeouts.WriteTotalTimeoutMultiplier=0;
				SetCommTimeouts(fd_, &timeouts);
				FlushFileBuffers(fd_);
				ret = true;
			}
			return ret;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	ボーレートの設定
			@param[in]	baud	ボーレート
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool set_baud(int baud)
		{
			DCB dcbSerialParams;
			GetCommState(fd_, &dcbSerialParams);
			dcbSerialParams.BaudRate = baud;
			return SetCommState(fd_, &dcbSerialParams) != 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	パリティーの設定
			@param[in]	parity	パリティー・タイプ
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool set_parity(PARITY parity)
		{
			DCB dcbSerialParams;
			GetCommState(fd_, &dcbSerialParams);
			switch(parity) {
			case PARITY::EVEN:
				dcbSerialParams.Parity = EVENPARITY;
				break;
			case PARITY::ODD:
				dcbSerialParams.Parity = ODDPARITY;
				break;
			case PARITY::NONE:
			default:
				dcbSerialParams.Parity = NOPARITY;
				break;
			}
			return SetCommState(fd_, &dcbSerialParams) != 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	DTR の設定（Data Terminal Ready)
			@param[in]	value	設定値
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool set_dtr(bool value)
		{
			int command;
			if(value) {
				command = SETDTR;
			} else {
				command = CLRDTR;
			}
			return EscapeCommFunction(fd_, command) != 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	RTS の設定（Request To Send)
			@param[in]	value	設定値
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool set_rts(bool value)
		{
			int command;
			if(value) {
				command = SETRTS;
			} else {
				command = CLRRTS;
			}
			return EscapeCommFunction(fd_, command) != 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	TXD の設定
			@param[in]	value	設定値
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool set_txd(bool value)
		{
			int command;
			if(value) {
				command = SETBREAK;
			} else {
				command = CLRBREAK;

			}
			return EscapeCommFunction(fd_, command) != 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	フラッシュ
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool flush()
		{
//			if(4 <= verbose_level) {
//				printf("\t\tFlush IO buffers\n");
//			}
			return PurgeComm(fd_, PURGE_RXCLEAR | PURGE_TXCLEAR) != 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	ライト
			@param[in]	src	転送元
			@param[in]	len	長さ（バイト）
			@return 書き込んだサイズ
		*/
		//-----------------------------------------------------------------//
		uint32_t write(const void* src, uint32_t len)
		{
#if 0
			if(4 <= verbose_level) {
				unsigned char *p = (unsigned char*)buf;
				unsigned int i;
				printf("\t\tsend(%u): ", len);
				for(i = len; 0 < i; --i) {
					printf("%02X ", *p++);
				}
				printf("\n");
			}
#endif
			int bytes_left = len;
			DWORD bytes_written;
			const uint8_t* p = reinterpret_cast<const uint8_t*>(src);
			do {
				if(0 == WriteFile(fd_, p, bytes_left, &bytes_written, NULL)) {
//					fprintf(stderr, "Failed to write to port.\n");
					return false;
				}
				p += bytes_written;
				bytes_left -= bytes_written;
			} while(0 < bytes_left) ;
			return len - bytes_left;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	リード
			@param[out]	dst	転送先
			@param[in]	len	長さ（バイト）
			@return 書き込んだサイズ
		*/
		//-----------------------------------------------------------------//
		uint32_t read(void *dst, int len)
		{
			int bytes_left = len;
			DWORD bytes_read;
			uint8_t* p = reinterpret_cast<uint8_t*>(dst);
			do {
				if(0 == ReadFile(fd_, p, bytes_left, &bytes_read, NULL)) {
///					fprintf(stderr, "Failed to read from port.\n");
//					last_error_ = 1;
					return 0;
				}
				if(0 == bytes_read) {
					break;
				}
				p += bytes_read;
				bytes_left -= bytes_read;
			} while(0 < bytes_left) ;

			uint32_t nbytes = len - bytes_left;
#if 0
			if(4 <= verbose_level) {
				p = dst;
				unsigned int i;
				printf("\t\trecv(%u): ", nbytes);
				for(i = nbytes; 0 < i; --i) {
					printf("%02X ", *pbuf++);
				}
				printf("\n");
			}
#endif
			return nbytes;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	クローズ
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool close() {
//			if(4 <= verbose_level) {
//				printf("\t\tClose port\n");
//			}
			return CloseHandle(fd_) != 0;
		}
	};
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Nagisa Sekiguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <poll.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#include <cstdlib>
#include <cassert>
#include <climits>
#include <csignal>
#include <cctype>

#include <constant.h>
#include <misc/util.hpp>
#include <misc/fatal.h>

#include "process.h"

#ifdef __CYGWIN__
static cc_t ttydefchars[NCCS] = {
            _POSIX_VDISABLE, CDISCARD, CEOL, CEOL2, CEOF, CERASE,
            CINTR, CKILL, CLNEXT, CMIN, CQUIT, CREPRINT, CSTART,
            CSTOP, CSUSP, CSWTCH, CTIME, CWERASE
    };
#else
#define TTYDEFCHARS
#include <sys/ttydefaults.h>
#endif

#define error_at fatal_perror

namespace process {

static WaitStatus inspectStatus(int status) {
    int s;
    WaitStatus::Kind type;
    if(WIFEXITED(status)) {
        s = WEXITSTATUS(status);
        type = WaitStatus::EXITED;
    } else if(WIFSIGNALED(status)) {
        s = WTERMSIG(status);
        type = WaitStatus::SIGNALED;
    } else if(WIFSTOPPED(status)) {
        s = WSTOPSIG(status);
        type = WaitStatus::STOPPED;
    } else {
        fatal("unsupported status\n");
    }
    return {.kind = type, .value = s};
}

// ########################
// ##     ProcHandle     ##
// ########################

ProcHandle::~ProcHandle() {
    if(*this) {
        kill(this->pid(), SIGKILL);
    }
    this->wait();
}

WaitStatus ProcHandle::wait() {
    if(this->pid() > -1) {
        // wait for exit
        int s;
        if(waitpid(this->pid(), &s, 0) < 0) {
            this->status_ = {.kind = WaitStatus::ERROR, .value = errno};
        } else {
            this->status_ = inspectStatus(s);
        }

        if(this->status_.isTerminated()) {
            close(this->in());
            close(this->out());
            close(this->err());

            this->detach();
        }
    }
    return this->status_;
}

static bool recvData(int fd, std::string &str) {
    char buf[64];
    unsigned int bufSize = ydsh::arraySize(buf);
    int readSize = read(fd, buf, bufSize);
    if(readSize <= 0) {
        return readSize == -1 && (errno == EAGAIN || errno == EINTR);
    }
    str.append(buf, readSize);
    return true;
}

std::pair<std::string, std::string> ProcHandle::readAll(int timeout) const {
    std::pair<std::string, std::string> output;
    if(this->out() < 0 && this->err() < 0) {
        return output;
    }

    struct pollfd pollfds[2]{};
    pollfds[0].fd = this->out();
    pollfds[0].events = POLLIN;
    pollfds[1].fd = this->err();
    pollfds[1].events = POLLIN;

    while(true) {
        constexpr unsigned int pollfdSize = ydsh::arraySize(pollfds);
        int ret = poll(pollfds, pollfdSize, timeout);
        if(ret <= 0) {
            if(ret == -1 && (errno == EINTR || errno == EAGAIN)) {
                continue;
            }
            break;
        }

        unsigned int breakCount = 0;
        for(unsigned int i = 0; i < pollfdSize; i++) {
            if(pollfds[i].revents) {
                if(!recvData(pollfds[i].fd, (i == 0 ? output.first : output.second))) {
                    breakCount++;
                    continue;
                }
            } else {
                breakCount++;
            }
        }
        if(breakCount == 2) {
            break;
        }
    }
    return output;
}

static void trimLastSpace(std::string &str) {
    for(; !str.empty() && isspace(str.back()); str.pop_back());
}

Output ProcHandle::waitAndGetResult(bool removeLastSpace) {
    auto output = this->readAll();
    auto status = this->wait();

    if(removeLastSpace) {
        trimLastSpace(output.first);
        trimLastSpace(output.second);
    }

    return {.status = status,
            .out = std::move(output.first),
            .err = std::move(output.second)};
}

// #########################
// ##     ProcBuilder     ##
// #########################

static void setPTYSetting(int fd, termios &term, unsigned short row, unsigned short col) {
    if(fd < 0) {
        return;
    }

    if(tcsetattr(fd, TCSAFLUSH, &term) == -1) {
        error_at("failed");
    }

    winsize ws;
    ws.ws_row = row;
    ws.ws_col = col;
    if(ioctl(fd, TIOCSWINSZ, &ws) == -1) {
        error_at("failed");
    }
}

ProcBuilder& ProcBuilder::addArgs(const std::vector<std::string> &values) {
    for(auto &e : values) {
        this->args.push_back(e);
    }
    return *this;
}

ProcHandle ProcBuilder::operator()() {
    return spawn(this->config, [&] {
        char *argv[this->args.size() + 1];
        for(unsigned int i = 0; i < this->args.size(); i++) {
            argv[i] = const_cast<char *>(this->args[i].c_str());
        }
        argv[this->args.size()] = nullptr;

        this->syncEnv();
        this->syncPWD();
        setPTYSetting(this->findPTY(), this->term, this->row, this->col);
        if(this->beforeExec) {
            this->beforeExec();
        }
        execvp(argv[0], argv);
        return -errno;
    });
}

static constexpr unsigned int READ_PIPE = 0;
static constexpr unsigned int WRITE_PIPE = 1;

static void loginPTY(int fd) {
    if(fd < 0) {
        return;
    }

    if(setsid() == -1) {
        error_at("failed");
    }

    if(ioctl(fd, TIOCSCTTY, 0) == -1) {
        error_at("failed");
    }
}

void xcfmakesane(termios &term) {
    term.c_iflag = TTYDEF_IFLAG;
    term.c_oflag = TTYDEF_OFLAG;
    term.c_lflag = TTYDEF_LFLAG;
    term.c_cflag = TTYDEF_CFLAG;
    cfsetispeed(&term, TTYDEF_SPEED);
    cfsetospeed(&term, TTYDEF_SPEED);

    memcpy(term.c_cc, ttydefchars, sizeof(ttydefchars));
}

static void openPTY(IOConfig config, int &masterFD, int &slaveFD) {
    if(config.in.is(IOConfig::PTY) ||
       config.out.is(IOConfig::PTY) ||
       config.err.is(IOConfig::PTY)) {
        int fd = posix_openpt(O_RDWR | O_NOCTTY);
        if(fd == -1) {
            error_at("open pty master failed");
        }
        if(grantpt(fd) != 0 || unlockpt(fd) != 0) {
            error_at("failed");
        }
        masterFD = fd;
        fd = open(ptsname(masterFD), O_RDWR | O_NOCTTY);
        if(fd == -1) {
            error_at("open pty slave failed");
        }
        termios term;
        cfmakeraw(&term);
        setPTYSetting(fd, term, 24, 80);
        slaveFD = fd;
    }
}

class StreamBuilder {
private:
    const IOConfig config;
    int inpipe[2];
    int outpipe[2];
    int errpipe[2];

    int masterFD{-1};
    int slaveFD{-1};

public:
    explicit StreamBuilder(IOConfig config) : config(config),
                                              inpipe{dup(this->config.in.fd), -1},
                                              outpipe{-1, dup(this->config.out.fd)},
                                              errpipe{-1, dup(this->config.err.fd)} {
    }

    void initPipe() {
        if(this->config.in.is(IOConfig::PIPE) && pipe(this->inpipe) < 0) {
            error_at("pipe creation failed");
        }
        if(this->config.out.is(IOConfig::PIPE) && pipe(this->outpipe) < 0) {
            error_at("pipe creation failed");
        }
        if(this->config.err.is(IOConfig::PIPE) && pipe(this->errpipe) < 0) {
            error_at("pipe creation failed");
        }
    }

    void init() {
        openPTY(this->config, this->masterFD, this->slaveFD);
        this->initPipe();
    }

    void setInParent() {
        close(this->slaveFD);
        this->closeInParent();
        if(this->masterFD > -1) {
            if(this->config.in.is(IOConfig::PTY)) {
                this->inpipe[WRITE_PIPE] = dup(this->masterFD);
            }
            if(this->config.out.is(IOConfig::PTY)) {
                this->outpipe[READ_PIPE] = dup(this->masterFD);
            }
            if(this->config.err.is(IOConfig::PTY)) {
                this->errpipe[READ_PIPE] = dup(this->masterFD);
            }
            close(this->masterFD);
        }
    }

    void initPTYSlave() {
        int fd = this->slaveFD;
        loginPTY(fd);

        if(this->config.in.is(IOConfig::PTY)) {
            this->inpipe[READ_PIPE] = dup(fd);
        }
        if(this->config.out.is(IOConfig::PTY)) {
            this->outpipe[WRITE_PIPE] = dup(fd);
        }
        if(this->config.err.is(IOConfig::PTY)) {
            this->errpipe[WRITE_PIPE] = dup(fd);
        }
        close(fd);
    }

    void closeInParent() {
        close(this->inpipe[READ_PIPE]);
        close(this->outpipe[WRITE_PIPE]);
        close(this->errpipe[WRITE_PIPE]);
    }

    void setInChild() {
        dup2(this->inpipe[READ_PIPE], STDIN_FILENO);
        dup2(this->outpipe[WRITE_PIPE], STDOUT_FILENO);
        dup2(this->errpipe[WRITE_PIPE], STDERR_FILENO);

        for(unsigned int i = 0; i < 2; i++) {
            close(this->inpipe[i]);
            close(this->outpipe[i]);
            close(this->errpipe[i]);
        }
    }

    void setChildStream() {
        close(this->masterFD);
        this->initPTYSlave();
        this->setInChild();
    }

    int inputWriter() const {
        return this->inpipe[WRITE_PIPE];
    }

    int outputReader() const {
        return this->outpipe[READ_PIPE];
    }

    int errorReader() const {
        return this->errpipe[READ_PIPE];
    }
};

ProcHandle ProcBuilder::spawnImpl(IOConfig config) {
    // flush standard stream due to prevent mixing io buffer
    fflush(stdin);
    fflush(stdout);
    fflush(stderr);

    StreamBuilder builder(config);
    builder.init();
    pid_t pid = fork();
    if(pid > 0) {
        builder.setInParent();
        return ProcHandle(pid, builder.inputWriter(), builder.outputReader(), builder.errorReader());
    } else if(pid == 0) {
        builder.setChildStream();
        return ProcHandle();
    } else {
        error_at("fork failed");
    }
}

void ProcBuilder::syncPWD() const {
    // change working dir
    if(!this->cwd.empty()) {
        if(chdir(this->cwd.c_str()) < 0) {
            error_at("chdir failed");
        }
    }

    // update PWD
    char *dir = realpath(".", nullptr);
    if(dir == nullptr) {
        error_at("current working directory is broken!!");
    }
    setenv(ydsh::ENV_PWD, dir, 1);
    free(dir);
}

void ProcBuilder::syncEnv() const {
    for(auto &pair : this->env) {
        setenv(pair.first.c_str(), pair.second.c_str(), 1);
    }
}

int ProcBuilder::findPTY() const {
    if(this->config.in.is(IOConfig::PTY)) {
        return STDIN_FILENO;
    }
    if(this->config.out.is(IOConfig::PTY)) {
        return STDOUT_FILENO;
    }
    if(this->config.err.is(IOConfig::PTY)) {
        return STDERR_FILENO;
    }
    return -1;
}

} // namespace process<commit_msg>some fix<commit_after>/*
 * Copyright (C) 2017-2018 Nagisa Sekiguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <poll.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#include <cstdlib>
#include <cassert>
#include <climits>
#include <csignal>
#include <cctype>

#include <constant.h>
#include <misc/util.hpp>
#include <misc/fatal.h>

#include "process.h"

#ifdef __CYGWIN__
static cc_t ttydefchars[NCCS] = {
            _POSIX_VDISABLE, CDISCARD, CEOL, CEOL2, CEOF, CERASE,
            CINTR, CKILL, CLNEXT, CMIN, CQUIT, CREPRINT, CSTART,
            CSTOP, CSUSP, CSWTCH, CTIME, CWERASE
    };
#else
#define TTYDEFCHARS
#include <sys/ttydefaults.h>
#endif

#define error_at fatal_perror

namespace process {

static WaitStatus inspectStatus(int status) {
    int s;
    WaitStatus::Kind type;
    if(WIFEXITED(status)) {
        s = WEXITSTATUS(status);
        type = WaitStatus::EXITED;
    } else if(WIFSIGNALED(status)) {
        s = WTERMSIG(status);
        type = WaitStatus::SIGNALED;
    } else if(WIFSTOPPED(status)) {
        s = WSTOPSIG(status);
        type = WaitStatus::STOPPED;
    } else {
        fatal("unsupported status\n");
    }
    return {.kind = type, .value = s};
}

// ########################
// ##     ProcHandle     ##
// ########################

ProcHandle::~ProcHandle() {
    if(*this) {
        kill(this->pid(), SIGKILL);
    }
    this->wait();
}

WaitStatus ProcHandle::wait() {
    if(this->pid() > -1) {
        // wait for exit
        int s;
        if(waitpid(this->pid(), &s, 0) < 0) {
            this->status_ = {.kind = WaitStatus::ERROR, .value = errno};
        } else {
            this->status_ = inspectStatus(s);
        }

        if(this->status_.isTerminated()) {
            close(this->in());
            close(this->out());
            close(this->err());

            this->detach();
        }
    }
    return this->status_;
}

static bool recvData(int fd, std::string &str) {
    char buf[64];
    unsigned int bufSize = ydsh::arraySize(buf);
    int readSize = read(fd, buf, bufSize);
    if(readSize <= 0) {
        return readSize == -1 && (errno == EAGAIN || errno == EINTR);
    }
    str.append(buf, readSize);
    return true;
}

std::pair<std::string, std::string> ProcHandle::readAll(int timeout) const {
    std::pair<std::string, std::string> output;
    if(this->out() < 0 && this->err() < 0) {
        return output;
    }

    struct pollfd pollfds[2]{};
    pollfds[0].fd = this->out();
    pollfds[0].events = POLLIN;
    pollfds[1].fd = this->err();
    pollfds[1].events = POLLIN;

    while(true) {
        constexpr unsigned int pollfdSize = ydsh::arraySize(pollfds);
        int ret = poll(pollfds, pollfdSize, timeout);
        if(ret <= 0) {
            if(ret == -1 && (errno == EINTR || errno == EAGAIN)) {
                continue;
            }
            break;
        }

        unsigned int breakCount = 0;
        for(unsigned int i = 0; i < pollfdSize; i++) {
            if(pollfds[i].revents & POLLIN) {
                if(!recvData(pollfds[i].fd, (i == 0 ? output.first : output.second))) {
                    breakCount++;
                    continue;
                }
            } else {
                breakCount++;
            }
        }
        if(breakCount == 2) {
            break;
        }
    }
    return output;
}

static void trimLastSpace(std::string &str) {
    for(; !str.empty() && isspace(str.back()); str.pop_back());
}

Output ProcHandle::waitAndGetResult(bool removeLastSpace) {
    auto output = this->readAll();
    auto status = this->wait();

    if(removeLastSpace) {
        trimLastSpace(output.first);
        trimLastSpace(output.second);
    }

    return {.status = status,
            .out = std::move(output.first),
            .err = std::move(output.second)};
}

// #########################
// ##     ProcBuilder     ##
// #########################

static void setPTYSetting(int fd, termios &term, unsigned short row, unsigned short col) {
    if(fd < 0) {
        return;
    }

    if(tcsetattr(fd, TCSAFLUSH, &term) == -1) {
        error_at("failed");
    }

    winsize ws;
    ws.ws_row = row;
    ws.ws_col = col;
    if(ioctl(fd, TIOCSWINSZ, &ws) == -1) {
        error_at("failed");
    }
}

ProcBuilder& ProcBuilder::addArgs(const std::vector<std::string> &values) {
    for(auto &e : values) {
        this->args.push_back(e);
    }
    return *this;
}

ProcHandle ProcBuilder::operator()() {
    return spawn(this->config, [&] {
        char *argv[this->args.size() + 1];
        for(unsigned int i = 0; i < this->args.size(); i++) {
            argv[i] = const_cast<char *>(this->args[i].c_str());
        }
        argv[this->args.size()] = nullptr;

        this->syncEnv();
        this->syncPWD();
        setPTYSetting(this->findPTY(), this->term, this->row, this->col);
        if(this->beforeExec) {
            this->beforeExec();
        }
        execvp(argv[0], argv);
        return -errno;
    });
}

static constexpr unsigned int READ_PIPE = 0;
static constexpr unsigned int WRITE_PIPE = 1;

static void loginPTY(int fd) {
    if(fd < 0) {
        return;
    }

    if(setsid() == -1) {
        error_at("failed");
    }

    if(ioctl(fd, TIOCSCTTY, 0) == -1) {
        error_at("failed");
    }
}

void xcfmakesane(termios &term) {
    term.c_iflag = TTYDEF_IFLAG;
    term.c_oflag = TTYDEF_OFLAG;
    term.c_lflag = TTYDEF_LFLAG;
    term.c_cflag = TTYDEF_CFLAG;
    cfsetispeed(&term, TTYDEF_SPEED);
    cfsetospeed(&term, TTYDEF_SPEED);

    memcpy(term.c_cc, ttydefchars, sizeof(ttydefchars));
}

static void openPTY(IOConfig config, int &masterFD, int &slaveFD) {
    if(config.in.is(IOConfig::PTY) ||
       config.out.is(IOConfig::PTY) ||
       config.err.is(IOConfig::PTY)) {
        int fd = posix_openpt(O_RDWR | O_NOCTTY);
        if(fd == -1) {
            error_at("open pty master failed");
        }
        if(grantpt(fd) != 0 || unlockpt(fd) != 0) {
            error_at("failed");
        }
        masterFD = fd;
        fd = open(ptsname(masterFD), O_RDWR | O_NOCTTY);
        if(fd == -1) {
            error_at("open pty slave failed");
        }
        termios term;
        cfmakeraw(&term);
        setPTYSetting(fd, term, 24, 80);
        slaveFD = fd;
    }
}

class StreamBuilder {
private:
    const IOConfig config;
    int inpipe[2];
    int outpipe[2];
    int errpipe[2];

    int masterFD{-1};
    int slaveFD{-1};

public:
    explicit StreamBuilder(IOConfig config) : config(config),
                                              inpipe{dup(this->config.in.fd), -1},
                                              outpipe{-1, dup(this->config.out.fd)},
                                              errpipe{-1, dup(this->config.err.fd)} {
    }

    void initPipe() {
        if(this->config.in.is(IOConfig::PIPE) && pipe(this->inpipe) < 0) {
            error_at("pipe creation failed");
        }
        if(this->config.out.is(IOConfig::PIPE) && pipe(this->outpipe) < 0) {
            error_at("pipe creation failed");
        }
        if(this->config.err.is(IOConfig::PIPE) && pipe(this->errpipe) < 0) {
            error_at("pipe creation failed");
        }
    }

    void init() {
        openPTY(this->config, this->masterFD, this->slaveFD);
        this->initPipe();
    }

    void setInParent() {
        close(this->slaveFD);
        this->closeInParent();
        if(this->masterFD > -1) {
            if(this->config.in.is(IOConfig::PTY)) {
                this->inpipe[WRITE_PIPE] = dup(this->masterFD);
            }
            if(this->config.out.is(IOConfig::PTY)) {
                this->outpipe[READ_PIPE] = dup(this->masterFD);
            }
            if(this->config.err.is(IOConfig::PTY)) {
                this->errpipe[READ_PIPE] = dup(this->masterFD);
            }
            close(this->masterFD);
        }
    }

    void initPTYSlave() {
        int fd = this->slaveFD;
        loginPTY(fd);

        if(this->config.in.is(IOConfig::PTY)) {
            this->inpipe[READ_PIPE] = dup(fd);
        }
        if(this->config.out.is(IOConfig::PTY)) {
            this->outpipe[WRITE_PIPE] = dup(fd);
        }
        if(this->config.err.is(IOConfig::PTY)) {
            this->errpipe[WRITE_PIPE] = dup(fd);
        }
        close(fd);
    }

    void closeInParent() {
        close(this->inpipe[READ_PIPE]);
        close(this->outpipe[WRITE_PIPE]);
        close(this->errpipe[WRITE_PIPE]);
    }

    void setInChild() {
        dup2(this->inpipe[READ_PIPE], STDIN_FILENO);
        dup2(this->outpipe[WRITE_PIPE], STDOUT_FILENO);
        dup2(this->errpipe[WRITE_PIPE], STDERR_FILENO);

        for(unsigned int i = 0; i < 2; i++) {
            close(this->inpipe[i]);
            close(this->outpipe[i]);
            close(this->errpipe[i]);
        }
    }

    void setChildStream() {
        close(this->masterFD);
        this->initPTYSlave();
        this->setInChild();
    }

    int inputWriter() const {
        return this->inpipe[WRITE_PIPE];
    }

    int outputReader() const {
        return this->outpipe[READ_PIPE];
    }

    int errorReader() const {
        return this->errpipe[READ_PIPE];
    }
};

ProcHandle ProcBuilder::spawnImpl(IOConfig config) {
    // flush standard stream due to prevent mixing io buffer
    fflush(stdin);
    fflush(stdout);
    fflush(stderr);

    StreamBuilder builder(config);
    builder.init();
    pid_t pid = fork();
    if(pid > 0) {
        builder.setInParent();
        return ProcHandle(pid, builder.inputWriter(), builder.outputReader(), builder.errorReader());
    } else if(pid == 0) {
        builder.setChildStream();
        return ProcHandle();
    } else {
        error_at("fork failed");
    }
}

void ProcBuilder::syncPWD() const {
    // change working dir
    if(!this->cwd.empty()) {
        if(chdir(this->cwd.c_str()) < 0) {
            error_at("chdir failed");
        }
    }

    // update PWD
    char *dir = realpath(".", nullptr);
    if(dir == nullptr) {
        error_at("current working directory is broken!!");
    }
    setenv(ydsh::ENV_PWD, dir, 1);
    free(dir);
}

void ProcBuilder::syncEnv() const {
    for(auto &pair : this->env) {
        setenv(pair.first.c_str(), pair.second.c_str(), 1);
    }
}

int ProcBuilder::findPTY() const {
    if(this->config.in.is(IOConfig::PTY)) {
        return STDIN_FILENO;
    }
    if(this->config.out.is(IOConfig::PTY)) {
        return STDOUT_FILENO;
    }
    if(this->config.err.is(IOConfig::PTY)) {
        return STDERR_FILENO;
    }
    return -1;
}

} // namespace process<|endoftext|>


<commit_before>/*
 * Copyright 2011 Intel Corporation.
 *
 * This program is licensed under the terms and conditions of the
 * Apache License, version 2.0.  The full text of the Apache License is at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

#include <QDebug>

#include <QtPlugin>

#include "implugin.h"

#include "imfeedmodelfilter.h"
#include "imservmodel.h"

#include <TelepathyQt4/ContactManager>
#include <TelepathyQt4/ChannelClassSpecList>
#include <TelepathyQt4/Types>
#include <TelepathyQt4/Debug>
#include <TelepathyQt4Yell/CallChannel>
#include <TelepathyQt4Yell/ChannelClassSpec>

IMPlugin::IMPlugin(QObject *parent): QObject(parent), McaFeedPlugin()
{
    Tp::registerTypes();

    qDebug() << "IMPlugin constructor";

    m_tpManager = new TelepathyManager(false);
    m_protocolsModel = new IMProtocolsModel(this);
    m_serviceModel = new IMServiceModel(m_tpManager, m_protocolsModel, this);
    connect(m_tpManager,
            SIGNAL(accountManagerReady()),
            SLOT(onAccountManagerReady()));

    m_tpManager->setProtocolNames(m_protocolsModel->protocolNames());

    mClientRegistrar = Tp::ClientRegistrar::create();

    initializeChannelObserver();
    initializeChannelApprover();

    connect(m_tpManager, SIGNAL(accountAvailable(Tp::AccountPtr)),
            m_serviceModel, SLOT(onAccountAvailable(Tp::AccountPtr)));
    connect(m_tpManager, SIGNAL(connectionAvailable(Tp::ConnectionPtr)),
            this, SLOT(onConnectionAvailble(Tp::ConnectionPtr)));

    // install translation catalogs
    loadTranslator();
    qApp->installTranslator(&appTranslator);

}

IMPlugin::~IMPlugin()
{
    qDebug() << "IMPlugin::~IMPlugin() terminating";
    mClientRegistrar->unregisterClients();
    delete m_serviceModel;
    delete m_tpManager;
    delete m_protocolsModel;
    mClientRegistrar->deleteLater();
    qDebug() << "IMPlugin::~IMPlugin() done terminating";
}

QAbstractItemModel *IMPlugin::serviceModel()
{
    return m_serviceModel;
}

QAbstractItemModel *IMPlugin::createFeedModel(const QString &service)
{
    qDebug() << "IMPlugin::createFeedModel: " << service;

    foreach (Tp::AccountPtr account, m_tpManager->accounts()) {
        if (account->uniqueIdentifier() == service) {
            IMFeedModel *model = new IMFeedModel(mObserver, account);

            connect(model, SIGNAL(applicationRunningChanged(bool)),
                    mChannelApprover, SLOT(setApplicationRunning(bool)));
            mFeedModels[service] = model;
            return model;
        }
    }
    return 0;
}

void IMPlugin::initializeChannelObserver()
{
    // setup the channel filters
    Tp::ChannelClassSpecList channelSpecList;

    channelSpecList.append(Tp::ChannelClassSpec::textChat());
    channelSpecList.append(Tp::ChannelClassSpec::textChatroom());
    channelSpecList.append(Tp::ChannelClassSpec::unnamedTextChat());
    channelSpecList.append(Tpy::ChannelClassSpec::mediaCall());
    channelSpecList.append(Tpy::ChannelClassSpec::audioCall());
    channelSpecList.append(Tpy::ChannelClassSpec::videoCall());
    channelSpecList.append(Tpy::ChannelClassSpec::videoCallWithAudio());
    channelSpecList.append(Tp::ChannelClassSpec::incomingFileTransfer());
    channelSpecList.append(Tp::ChannelClassSpec::outgoingFileTransfer());

    // create the channel observer
    mObserver = new PanelsChannelObserver(channelSpecList, true);
    Tp::AbstractClientPtr observer(mObserver);

    // register the observer
    mClientRegistrar->registerClient(observer, "MeeGoIMPanelsObserver");
}

void IMPlugin::initializeChannelApprover()
{
    // create the channel approver
    mChannelApprover = new IMChannelApprover();
    Tp::AbstractClientPtr approver(mChannelApprover);

    // register the approver
    mClientRegistrar->registerClient(approver, "MeeGoIMPanelsApprover");
}

void IMPlugin::onConnectionAvailable(Tp::ConnectionPtr conn)
{
    // find the account related to the connection and connect
    // the contact manager to the publication request slot on the model
    foreach (IMFeedModel *model, mFeedModels) {
        if (!model->account()->connection().isNull()) {
            if (model->account()->connection() == conn) {
                Tp::ContactManagerPtr manager = model->account()->connection()->contactManager();
                connect(manager.data(), SIGNAL(presencePublicationRequested(Tp::Contacts,Tp::Channel::GroupMemberChangeDetails)),
                        model, SLOT(onPresencePublicationRequested(Tp::Contacts)));
                connect(manager.data(), SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts,Tp::Channel::GroupMemberChangeDetails)),
                        model, SLOT(onAllKnownContactsChanged(Tp::Contacts,Tp::Contacts,Tp::Channel::GroupMemberChangeDetails)));
                connect(model, SIGNAL(acceptContact(Tp::AccountPtr,QString)), SLOT(onAcceptContact(Tp::AccountPtr,QString)));
                connect(model,SIGNAL(rejectContact(Tp::AccountPtr,QString)), SLOT(onRejectContact(Tp::AccountPtr,QString)));

                // Look for friend requests
                Tp::Contacts contacts = manager->allKnownContacts();
                QList<Tp::ContactPtr> friendRequests;
                foreach (Tp::ContactPtr contact, contacts) {
                    if (contact->publishState() == Tp::Contact::PresenceStateAsk) {
                        friendRequests.append(contact);
                    }
                }
                // Add the friend requests to the model
                if (friendRequests.count() > 0) {
                    model->onPresencePublicationRequested(Tp::Contacts().fromList(friendRequests));
                }
            }
        }
    }
}

void IMPlugin::onAcceptContact(Tp::AccountPtr account, QString contactId)
{
    foreach (IMFeedModel *model, mFeedModels) {
        if (model->account()->uniqueIdentifier() == account->uniqueIdentifier()) {
            if (!model->account()->connection().isNull()) {
                Tp::ContactManagerPtr manager = model->account()->connection()->contactManager();

                Tp::Contacts contacts = manager->allKnownContacts();
                QList<Tp::ContactPtr> contactsToAppend;
                QList<Tp::ContactPtr>  contactsList = contacts.toList();
                foreach (Tp::ContactPtr contact, contactsList) {
                    if (contact->id() == contactId) {
                        contactsToAppend.append(contact);
                        break;
                    }
                }
                manager->authorizePresencePublication(contactsToAppend);
            }
        }
    }
}

void IMPlugin::onRejectContact(Tp::AccountPtr account, QString contactId)
{
    foreach (IMFeedModel *model, mFeedModels) {
        if (model->account()->uniqueIdentifier() == account->uniqueIdentifier()) {
            if (!model->account()->connection().isNull()) {
                Tp::ContactManagerPtr manager = model->account()->connection()->contactManager();

                Tp::Contacts contacts = manager->allKnownContacts();
                QList<Tp::ContactPtr> contactsToAppend;
                QList<Tp::ContactPtr>  contactsList = contacts.toList();
                foreach (Tp::ContactPtr contact, contactsList) {
                    if (contact->id() == contactId) {
                        contactsToAppend.append(contact);
                        break;
                    }
                }
                manager->removePresencePublication(contactsToAppend);
            }
        }
    }
}

McaSearchableFeed *IMPlugin::createSearchModel(const QString &service, const QString &searchText)
{
    qDebug() << "IMPlugin::createSearchModel: " << service << "searchText: " << searchText;

    if (mFeedModels.contains(service)) {
        IMFeedModelFilter *filter = new IMFeedModelFilter(mFeedModels[service], this);
        filter->setSearchText(searchText);
        return filter;
    }
    return 0;
}

void IMPlugin::loadTranslator()
{
    appTranslator.load("meego-app-im_" + QLocale::system().name() + ".qm",
                       QLibraryInfo::location(QLibraryInfo::TranslationsPath));
}

Q_EXPORT_PLUGIN2(im_panels_plugin, IMPlugin)
<commit_msg>Fix a typo in the slot name<commit_after>/*
 * Copyright 2011 Intel Corporation.
 *
 * This program is licensed under the terms and conditions of the
 * Apache License, version 2.0.  The full text of the Apache License is at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

#include <QDebug>

#include <QtPlugin>

#include "implugin.h"

#include "imfeedmodelfilter.h"
#include "imservmodel.h"

#include <TelepathyQt4/ContactManager>
#include <TelepathyQt4/ChannelClassSpecList>
#include <TelepathyQt4/Types>
#include <TelepathyQt4/Debug>
#include <TelepathyQt4Yell/CallChannel>
#include <TelepathyQt4Yell/ChannelClassSpec>

IMPlugin::IMPlugin(QObject *parent): QObject(parent), McaFeedPlugin()
{
    Tp::registerTypes();

    qDebug() << "IMPlugin constructor";

    m_tpManager = new TelepathyManager(false);
    m_protocolsModel = new IMProtocolsModel(this);
    m_serviceModel = new IMServiceModel(m_tpManager, m_protocolsModel, this);
    connect(m_tpManager,
            SIGNAL(accountManagerReady()),
            SLOT(onAccountManagerReady()));

    m_tpManager->setProtocolNames(m_protocolsModel->protocolNames());

    mClientRegistrar = Tp::ClientRegistrar::create();

    initializeChannelObserver();
    initializeChannelApprover();

    connect(m_tpManager, SIGNAL(accountAvailable(Tp::AccountPtr)),
            m_serviceModel, SLOT(onAccountAvailable(Tp::AccountPtr)));
    connect(m_tpManager, SIGNAL(connectionAvailable(Tp::ConnectionPtr)),
            this, SLOT(onConnectionAvailable(Tp::ConnectionPtr)));

    // install translation catalogs
    loadTranslator();
    qApp->installTranslator(&appTranslator);

}

IMPlugin::~IMPlugin()
{
    qDebug() << "IMPlugin::~IMPlugin() terminating";
    mClientRegistrar->unregisterClients();
    delete m_serviceModel;
    delete m_tpManager;
    delete m_protocolsModel;
    mClientRegistrar->deleteLater();
    qDebug() << "IMPlugin::~IMPlugin() done terminating";
}

QAbstractItemModel *IMPlugin::serviceModel()
{
    return m_serviceModel;
}

QAbstractItemModel *IMPlugin::createFeedModel(const QString &service)
{
    qDebug() << "IMPlugin::createFeedModel: " << service;

    foreach (Tp::AccountPtr account, m_tpManager->accounts()) {
        if (account->uniqueIdentifier() == service) {
            IMFeedModel *model = new IMFeedModel(mObserver, account);

            connect(model, SIGNAL(applicationRunningChanged(bool)),
                    mChannelApprover, SLOT(setApplicationRunning(bool)));
            mFeedModels[service] = model;
            return model;
        }
    }
    return 0;
}

void IMPlugin::initializeChannelObserver()
{
    // setup the channel filters
    Tp::ChannelClassSpecList channelSpecList;

    channelSpecList.append(Tp::ChannelClassSpec::textChat());
    channelSpecList.append(Tp::ChannelClassSpec::textChatroom());
    channelSpecList.append(Tp::ChannelClassSpec::unnamedTextChat());
    channelSpecList.append(Tpy::ChannelClassSpec::mediaCall());
    channelSpecList.append(Tpy::ChannelClassSpec::audioCall());
    channelSpecList.append(Tpy::ChannelClassSpec::videoCall());
    channelSpecList.append(Tpy::ChannelClassSpec::videoCallWithAudio());
    channelSpecList.append(Tp::ChannelClassSpec::incomingFileTransfer());
    channelSpecList.append(Tp::ChannelClassSpec::outgoingFileTransfer());

    // create the channel observer
    mObserver = new PanelsChannelObserver(channelSpecList, true);
    Tp::AbstractClientPtr observer(mObserver);

    // register the observer
    mClientRegistrar->registerClient(observer, "MeeGoIMPanelsObserver");
}

void IMPlugin::initializeChannelApprover()
{
    // create the channel approver
    mChannelApprover = new IMChannelApprover();
    Tp::AbstractClientPtr approver(mChannelApprover);

    // register the approver
    mClientRegistrar->registerClient(approver, "MeeGoIMPanelsApprover");
}

void IMPlugin::onConnectionAvailable(Tp::ConnectionPtr conn)
{
    // find the account related to the connection and connect
    // the contact manager to the publication request slot on the model
    foreach (IMFeedModel *model, mFeedModels) {
        if (!model->account()->connection().isNull()) {
            if (model->account()->connection() == conn) {
                Tp::ContactManagerPtr manager = model->account()->connection()->contactManager();
                connect(manager.data(), SIGNAL(presencePublicationRequested(Tp::Contacts,Tp::Channel::GroupMemberChangeDetails)),
                        model, SLOT(onPresencePublicationRequested(Tp::Contacts)));
                connect(manager.data(), SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts,Tp::Channel::GroupMemberChangeDetails)),
                        model, SLOT(onAllKnownContactsChanged(Tp::Contacts,Tp::Contacts,Tp::Channel::GroupMemberChangeDetails)));
                connect(model, SIGNAL(acceptContact(Tp::AccountPtr,QString)), SLOT(onAcceptContact(Tp::AccountPtr,QString)));
                connect(model,SIGNAL(rejectContact(Tp::AccountPtr,QString)), SLOT(onRejectContact(Tp::AccountPtr,QString)));

                // Look for friend requests
                Tp::Contacts contacts = manager->allKnownContacts();
                QList<Tp::ContactPtr> friendRequests;
                foreach (Tp::ContactPtr contact, contacts) {
                    if (contact->publishState() == Tp::Contact::PresenceStateAsk) {
                        friendRequests.append(contact);
                    }
                }
                // Add the friend requests to the model
                if (friendRequests.count() > 0) {
                    model->onPresencePublicationRequested(Tp::Contacts().fromList(friendRequests));
                }
            }
        }
    }
}

void IMPlugin::onAcceptContact(Tp::AccountPtr account, QString contactId)
{
    foreach (IMFeedModel *model, mFeedModels) {
        if (model->account()->uniqueIdentifier() == account->uniqueIdentifier()) {
            if (!model->account()->connection().isNull()) {
                Tp::ContactManagerPtr manager = model->account()->connection()->contactManager();

                Tp::Contacts contacts = manager->allKnownContacts();
                QList<Tp::ContactPtr> contactsToAppend;
                QList<Tp::ContactPtr>  contactsList = contacts.toList();
                foreach (Tp::ContactPtr contact, contactsList) {
                    if (contact->id() == contactId) {
                        contactsToAppend.append(contact);
                        break;
                    }
                }
                manager->authorizePresencePublication(contactsToAppend);
            }
        }
    }
}

void IMPlugin::onRejectContact(Tp::AccountPtr account, QString contactId)
{
    foreach (IMFeedModel *model, mFeedModels) {
        if (model->account()->uniqueIdentifier() == account->uniqueIdentifier()) {
            if (!model->account()->connection().isNull()) {
                Tp::ContactManagerPtr manager = model->account()->connection()->contactManager();

                Tp::Contacts contacts = manager->allKnownContacts();
                QList<Tp::ContactPtr> contactsToAppend;
                QList<Tp::ContactPtr>  contactsList = contacts.toList();
                foreach (Tp::ContactPtr contact, contactsList) {
                    if (contact->id() == contactId) {
                        contactsToAppend.append(contact);
                        break;
                    }
                }
                manager->removePresencePublication(contactsToAppend);
            }
        }
    }
}

McaSearchableFeed *IMPlugin::createSearchModel(const QString &service, const QString &searchText)
{
    qDebug() << "IMPlugin::createSearchModel: " << service << "searchText: " << searchText;

    if (mFeedModels.contains(service)) {
        IMFeedModelFilter *filter = new IMFeedModelFilter(mFeedModels[service], this);
        filter->setSearchText(searchText);
        return filter;
    }
    return 0;
}

void IMPlugin::loadTranslator()
{
    appTranslator.load("meego-app-im_" + QLocale::system().name() + ".qm",
                       QLibraryInfo::location(QLibraryInfo::TranslationsPath));
}

Q_EXPORT_PLUGIN2(im_panels_plugin, IMPlugin)
<|endoftext|>


<commit_before>#include "intnw_net_stats_wrapper.h"
#include "intnw_instruments_net_stats_wrapper.h"
#include "debug.h"

InstrumentsWrappedNetStats::InstrumentsWrappedNetStats(const std::string& network)
    : first_update(true)
{
    dbgprintf("creating InstrumentsWrappedNetStats %p\n", this);

    bw_up_estimator = create_external_estimator((network + "-bandwidth").c_str());
    rtt_estimator = create_external_estimator((network + "-RTT").c_str());
}

InstrumentsWrappedNetStats::~InstrumentsWrappedNetStats()
{
    dbgprintf("destroying InstrumentsWrappedNetStats %p\n", this);

    free_external_estimator(bw_up_estimator);
    free_external_estimator(rtt_estimator);
}

double InstrumentsWrappedNetStats::get_bandwidth_up(instruments_context_t ctx)
{
    return get_estimator_value(ctx, bw_up_estimator);
}

double InstrumentsWrappedNetStats::get_rtt(instruments_context_t ctx)
{
    return get_estimator_value(ctx, rtt_estimator);
}

void InstrumentsWrappedNetStats::update(double bw_up, double bw_estimate,
                                        double RTT_seconds, double RTT_estimate)
{
    if (bw_up == 0 && RTT_seconds == 0) {
        // ignore; not a real measurement
        return;
    }

    // XXX: hackish.  Should separate bw and RTT updates.
    do {
        if (bw_up > 0.0) {
            add_observation(bw_up_estimator, bw_up, bw_estimate);
        }
        if (RTT_seconds > 0.0) {
            add_observation(rtt_estimator, RTT_seconds, RTT_estimate);
        }
    } while (was_first_update());
}

bool
InstrumentsWrappedNetStats::was_first_update()
{
    bool ret = first_update;
    first_update = false;
    return ret;
}
<commit_msg>Forgot to actually set the range hints on the estimators.<commit_after>#include "intnw_net_stats_wrapper.h"
#include "intnw_instruments_net_stats_wrapper.h"
#include "debug.h"
#include "config.h"

#include <instruments_private.h>

#include <assert.h>

#include <string>
#include <map>
using std::string; using std::map;

static EstimatorRangeHints
get_range_hints(const string& network, const string& type)
{
    map<string, map<string, decltype(&Config::getCellularRttRangeHints)> > getters = {
        { "wifi", {
                { "bandwidth", &Config::getWifiBandwidthRangeHints },
                { "RTT", &Config::getWifiRttRangeHints }
            },
        },
        { "cellular", {
                { "bandwidth", &Config::getCellularBandwidthRangeHints },
                { "RTT", &Config::getCellularRttRangeHints }
            }

        }
    };
    assert(getters.count(network) > 0 &&
           getters[network].count(type) > 0);
    auto getter = getters[network][type];
    Config *config = Config::getInstance();
    return (config->*getter)();
}

InstrumentsWrappedNetStats::InstrumentsWrappedNetStats(const std::string& network)
    : first_update(true)
{
    dbgprintf("creating InstrumentsWrappedNetStats %p\n", this);

    bw_up_estimator = create_external_estimator((network + "-bandwidth").c_str());
    rtt_estimator = create_external_estimator((network + "-RTT").c_str());

    EstimatorRangeHints bw_hints = get_range_hints(network, "bandwidth");
    EstimatorRangeHints rtt_hints = get_range_hints(network, "RTT");
    set_estimator_range_hints(bw_up_estimator, bw_hints.min, bw_hints.max, bw_hints.num_bins);
    set_estimator_range_hints(rtt_estimator, rtt_hints.min, rtt_hints.max, rtt_hints.num_bins);
}

InstrumentsWrappedNetStats::~InstrumentsWrappedNetStats()
{
    dbgprintf("destroying InstrumentsWrappedNetStats %p\n", this);

    free_external_estimator(bw_up_estimator);
    free_external_estimator(rtt_estimator);
}

double InstrumentsWrappedNetStats::get_bandwidth_up(instruments_context_t ctx)
{
    return get_estimator_value(ctx, bw_up_estimator);
}

double InstrumentsWrappedNetStats::get_rtt(instruments_context_t ctx)
{
    return get_estimator_value(ctx, rtt_estimator);
}

void InstrumentsWrappedNetStats::update(double bw_up, double bw_estimate,
                                        double RTT_seconds, double RTT_estimate)
{
    if (bw_up == 0 && RTT_seconds == 0) {
        // ignore; not a real measurement
        return;
    }

    // XXX: hackish.  Should separate bw and RTT updates.
    do {
        if (bw_up > 0.0) {
            add_observation(bw_up_estimator, bw_up, bw_estimate);
        }
        if (RTT_seconds > 0.0) {
            add_observation(rtt_estimator, RTT_seconds, RTT_estimate);
        }
    } while (was_first_update());
}

bool
InstrumentsWrappedNetStats::was_first_update()
{
    bool ret = first_update;
    first_update = false;
    return ret;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkProgrammableGlyphFilter.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkProgrammableGlyphFilter.h"
#include "vtkTransform.h"
#include "vtkVectors.h"
#include "vtkNormals.h"
#include "vtkMath.h"

// Construct object with scaling on, scaling mode is by scalar value,
// scale factor = 1.0, the range is (0,1), orient geometry is on, and
// orientation is by vector. Clamping and indexing are turned off. No
// initial sources are defined.
vtkProgrammableGlyphFilter::vtkProgrammableGlyphFilter()
{
  this->Source = NULL;

  this->GlyphMethod = NULL;
  this->GlyphMethodArgDelete = NULL;
  this->GlyphMethodArg = NULL;

  this->Point[0] = this->Point[1] = this->Point[2] = 0.0;
  this->PointId = -1;
  this->PointData = NULL;

  this->ColorMode = VTK_COLOR_BY_INPUT;
}

vtkProgrammableGlyphFilter::~vtkProgrammableGlyphFilter()
{
  if ((this->GlyphMethodArg)&&(this->GlyphMethodArgDelete))
    {
    (*this->GlyphMethodArgDelete)(this->GlyphMethodArg);
    }

  this->SetSource(NULL);
}

void vtkProgrammableGlyphFilter::Execute()
{
  vtkDataSet *input = this->GetInput();
  vtkPointData *inputPD = input->GetPointData();
  vtkCellData *inputCD = input->GetCellData();
  vtkPolyData *output = this->GetOutput();
  vtkPointData *outputPD = output->GetPointData();
  vtkCellData *outputCD = output->GetCellData();
  vtkPoints *newPts, *sourcePts;
  vtkScalars *ptScalars=NULL, *cellScalars=NULL;
  vtkScalars *inPtScalars, *inCellScalars;
  int numPts = input->GetNumberOfPoints();
  vtkPointData *sourcePD;
  vtkCellData *sourceCD;
  int numSourcePts, numSourceCells, ptOffset=0, scalarOffset;
  int cellId, ptId, id, i, idx, npts;
  vtkIdList *pts=vtkIdList::New();
  vtkIdList *cellPts;
  pts->Allocate(VTK_CELL_SIZE);
  vtkCell *cell;

  // Initialize
  vtkDebugMacro(<<"Generating programmable glyphs!");

  if ( numPts < 1 )
    {
    vtkErrorMacro(<<"No input points to glyph");
    }

  sourcePD = this->Source->GetPointData();
  sourceCD = this->Source->GetCellData();
  numSourcePts = this->Source->GetNumberOfPoints();
  numSourceCells = this->Source->GetNumberOfCells();

  outputPD->CopyScalarsOff(); //'cause we control the coloring process
  outputCD->CopyScalarsOff();

  output->Allocate(numSourceCells*numPts,numSourceCells*numPts);
  outputPD->CopyAllocate(sourcePD, numSourcePts*numPts, numSourcePts*numPts);
  outputCD->CopyAllocate(sourceCD, numSourceCells*numPts, numSourceCells*numPts);
  newPts = vtkPoints::New();
  newPts->Allocate(numSourcePts*numPts);

  // figure out how to color the data and setup
  if ( this->ColorMode == VTK_COLOR_BY_INPUT )
    {
    if ( (inPtScalars = inputPD->GetScalars()) )
      {
      ptScalars = vtkScalars::New();
      ptScalars->Allocate(numSourcePts*numPts);
      }
    if ( (inCellScalars = inputCD->GetScalars()) )
      {
      cellScalars = vtkScalars::New();
      cellScalars->Allocate(numSourcePts*numPts);
      }
    }
  else // VTK_COLOR_BY_SOURCE
    {
    if ( (inPtScalars = sourcePD->GetScalars()) )
      {
      ptScalars = vtkScalars::New();
      ptScalars->Allocate(numSourcePts*numPts);
      }
    if ( (inCellScalars = sourceCD->GetScalars()) )
      {
      cellScalars = vtkScalars::New();
      cellScalars->Allocate(numSourcePts*numPts);
      }
    }

  // Loop over all points, invoking glyph method and Update(), then append output
  // of source to output of this filter.
  //
  this->Updating = 1; // to prevent infinite recursion
  this->PointData = input->GetPointData();
  for (this->PointId=0; this->PointId < numPts; this->PointId++)
    {
    if ( ! (this->PointId % 10000) )
      {
      this->UpdateProgress ((float)this->PointId/numPts);
      if (this->GetAbortExecute()) break;
      }

    input->GetPoint(this->PointId, this->Point);

    if ( this->GlyphMethod )
      {
      (*this->GlyphMethod)(this->GlyphMethodArg);
      }

    if ( this->Source )
      {
      this->Source->Update();

      sourcePts = this->Source->GetPoints();
      numSourcePts = this->Source->GetNumberOfPoints();
      numSourceCells = this->Source->GetNumberOfCells();
      sourcePD = this->Source->GetPointData();
      sourceCD = this->Source->GetCellData();

      // Copy all data from source to output.
      for (ptId=0; ptId < numSourcePts; ptId++)
        {
        id = newPts->InsertNextPoint(sourcePts->GetPoint(ptId));
        outputPD->CopyData(sourcePD, ptId, id);
        }

      for (cellId=0; cellId < numSourceCells; cellId++)
        {
        cell = this->Source->GetCell(cellId);
        cellPts = cell->GetPointIds();
        npts = cellPts->GetNumberOfIds();
        for (pts->Reset(), i=0; i < npts; i++)
          {
          pts->InsertId(i,cellPts->GetId(i) + ptOffset);
          }
        id = output->InsertNextCell(cell->GetCellType(),pts);
        outputCD->CopyData(sourceCD, cellId, id);
        }

      // If we're coloring the output with scalars, do that now
      if ( ptScalars )
        {
        for (ptId=0; ptId < numSourcePts; ptId++)
          {
          idx = (this->ColorMode == VTK_COLOR_BY_INPUT ? this->PointId : ptId);
          ptScalars->InsertNextScalar(inPtScalars->GetScalar(idx));
          }
        }
      else if ( cellScalars )
        {
        for (cellId=0; cellId < numSourceCells; cellId++)
          {
          idx = (this->ColorMode == VTK_COLOR_BY_INPUT ? this->PointId : cellId);
          cellScalars->InsertNextScalar(inCellScalars->GetScalar(idx));
          }
        }

      ptOffset += numSourcePts;

      }//if a source is available
    } //for all input points

  this->Updating = 0;

  pts->Delete();

  output->SetPoints(newPts);
  newPts->Delete();

  if ( ptScalars )
    {
    outputPD->SetScalars(ptScalars);
    ptScalars->Delete();
    }

  if ( cellScalars )
    {
    outputCD->SetScalars(cellScalars);
    cellScalars->Delete();
    }

  output->Squeeze();
}

// Override update method because execution can branch two ways (via Input
// and Source).
void vtkProgrammableGlyphFilter::Update()
{
  // make sure input is available
  if ( this->Input == NULL || this->Source == NULL )
    {
    vtkErrorMacro(<< "No input or source...can't execute!");
    return;
    }

  // prevent chasing our tail
  if (this->Updating) return;

  this->Updating = 1;
  this->Input->Update();
  if ( this->Source ) this->Source->Update();
  this->Updating = 0;

  if (this->Input->GetMTime() > this->ExecuteTime ||
  (this->Source && this->Source->GetMTime() > this->ExecuteTime) ||
  this->GetMTime() > this->ExecuteTime )
    {
    if ( this->Input->GetDataReleased() ) this->Input->ForceUpdate();
    if ( this->Source && this->Source->GetDataReleased() )
      this->Source->ForceUpdate();

    if ( this->StartMethod ) (*this->StartMethod)(this->StartMethodArg);
    this->Output->Initialize(); //clear output
    // reset AbortExecute flag and Progress
    this->AbortExecute = 0;
    this->Progress = 0.0;
    this->Execute();
    this->ExecuteTime.Modified();
    if ( !this->AbortExecute ) this->UpdateProgress(1.0);
    this->SetDataReleased(0);
    if ( this->EndMethod ) (*this->EndMethod)(this->EndMethodArg);
    }

  if ( this->Input->ShouldIReleaseData() ) this->Input->ReleaseData();
  if ( this->Source && this->Source->ShouldIReleaseData() )
    this->Source->ReleaseData();
}

// Specify function to be called before object executes.
void vtkProgrammableGlyphFilter::SetGlyphMethod(void (*f)(void *), void *arg)
{
  if ( f != this->GlyphMethod || arg != this->GlyphMethodArg )
    {
    // delete the current arg if there is one and a delete meth
    if ((this->GlyphMethodArg)&&(this->GlyphMethodArgDelete))
      {
      (*this->GlyphMethodArgDelete)(this->GlyphMethodArg);
      }
    this->GlyphMethod = f;
    this->GlyphMethodArg = arg;
    this->Modified();
    }
}

// Set the arg delete method. This is used to free user memory.
void vtkProgrammableGlyphFilter::SetGlyphMethodArgDelete(void (*f)(void *))
{
  if ( f != this->GlyphMethodArgDelete)
    {
    this->GlyphMethodArgDelete = f;
    this->Modified();
    }
}

// Description:
// Return the method of coloring as a descriptive character string.
char *vtkProgrammableGlyphFilter::GetColorModeAsString(void)
{
  if ( this->ColorMode == VTK_COLOR_BY_INPUT )
    {
    return "ColorByInput";
    }
  else
    {
    return "ColorBySource";
    }
}

void vtkProgrammableGlyphFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkDataSetToPolyDataFilter::PrintSelf(os,indent);

  os << indent << "Source: " << (void *)this->Source << "\n";

  os << indent << "Color Mode: " << this->GetColorModeAsString() << endl;

  if ( this->GlyphMethod )
    {
    os << indent << "Glyph Method defined\n";
    }
  else
    {
    os << indent << "No Glyph Method\n";
    }

}
<commit_msg>ERR: PrintSelf defects.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkProgrammableGlyphFilter.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkProgrammableGlyphFilter.h"
#include "vtkTransform.h"
#include "vtkVectors.h"
#include "vtkNormals.h"
#include "vtkMath.h"

// Construct object with scaling on, scaling mode is by scalar value,
// scale factor = 1.0, the range is (0,1), orient geometry is on, and
// orientation is by vector. Clamping and indexing are turned off. No
// initial sources are defined.
vtkProgrammableGlyphFilter::vtkProgrammableGlyphFilter()
{
  this->Source = NULL;

  this->GlyphMethod = NULL;
  this->GlyphMethodArgDelete = NULL;
  this->GlyphMethodArg = NULL;

  this->Point[0] = this->Point[1] = this->Point[2] = 0.0;
  this->PointId = -1;
  this->PointData = NULL;

  this->ColorMode = VTK_COLOR_BY_INPUT;
}

vtkProgrammableGlyphFilter::~vtkProgrammableGlyphFilter()
{
  if ((this->GlyphMethodArg)&&(this->GlyphMethodArgDelete))
    {
    (*this->GlyphMethodArgDelete)(this->GlyphMethodArg);
    }

  this->SetSource(NULL);
}

void vtkProgrammableGlyphFilter::Execute()
{
  vtkDataSet *input = this->GetInput();
  vtkPointData *inputPD = input->GetPointData();
  vtkCellData *inputCD = input->GetCellData();
  vtkPolyData *output = this->GetOutput();
  vtkPointData *outputPD = output->GetPointData();
  vtkCellData *outputCD = output->GetCellData();
  vtkPoints *newPts, *sourcePts;
  vtkScalars *ptScalars=NULL, *cellScalars=NULL;
  vtkScalars *inPtScalars, *inCellScalars;
  int numPts = input->GetNumberOfPoints();
  vtkPointData *sourcePD;
  vtkCellData *sourceCD;
  int numSourcePts, numSourceCells, ptOffset=0, scalarOffset;
  int cellId, ptId, id, i, idx, npts;
  vtkIdList *pts=vtkIdList::New();
  vtkIdList *cellPts;
  pts->Allocate(VTK_CELL_SIZE);
  vtkCell *cell;

  // Initialize
  vtkDebugMacro(<<"Generating programmable glyphs!");

  if ( numPts < 1 )
    {
    vtkErrorMacro(<<"No input points to glyph");
    }

  sourcePD = this->Source->GetPointData();
  sourceCD = this->Source->GetCellData();
  numSourcePts = this->Source->GetNumberOfPoints();
  numSourceCells = this->Source->GetNumberOfCells();

  outputPD->CopyScalarsOff(); //'cause we control the coloring process
  outputCD->CopyScalarsOff();

  output->Allocate(numSourceCells*numPts,numSourceCells*numPts);
  outputPD->CopyAllocate(sourcePD, numSourcePts*numPts, numSourcePts*numPts);
  outputCD->CopyAllocate(sourceCD, numSourceCells*numPts, numSourceCells*numPts);
  newPts = vtkPoints::New();
  newPts->Allocate(numSourcePts*numPts);

  // figure out how to color the data and setup
  if ( this->ColorMode == VTK_COLOR_BY_INPUT )
    {
    if ( (inPtScalars = inputPD->GetScalars()) )
      {
      ptScalars = vtkScalars::New();
      ptScalars->Allocate(numSourcePts*numPts);
      }
    if ( (inCellScalars = inputCD->GetScalars()) )
      {
      cellScalars = vtkScalars::New();
      cellScalars->Allocate(numSourcePts*numPts);
      }
    }
  else // VTK_COLOR_BY_SOURCE
    {
    if ( (inPtScalars = sourcePD->GetScalars()) )
      {
      ptScalars = vtkScalars::New();
      ptScalars->Allocate(numSourcePts*numPts);
      }
    if ( (inCellScalars = sourceCD->GetScalars()) )
      {
      cellScalars = vtkScalars::New();
      cellScalars->Allocate(numSourcePts*numPts);
      }
    }

  // Loop over all points, invoking glyph method and Update(), then append output
  // of source to output of this filter.
  //
  this->Updating = 1; // to prevent infinite recursion
  this->PointData = input->GetPointData();
  for (this->PointId=0; this->PointId < numPts; this->PointId++)
    {
    if ( ! (this->PointId % 10000) )
      {
      this->UpdateProgress ((float)this->PointId/numPts);
      if (this->GetAbortExecute()) break;
      }

    input->GetPoint(this->PointId, this->Point);

    if ( this->GlyphMethod )
      {
      (*this->GlyphMethod)(this->GlyphMethodArg);
      }

    if ( this->Source )
      {
      this->Source->Update();

      sourcePts = this->Source->GetPoints();
      numSourcePts = this->Source->GetNumberOfPoints();
      numSourceCells = this->Source->GetNumberOfCells();
      sourcePD = this->Source->GetPointData();
      sourceCD = this->Source->GetCellData();

      // Copy all data from source to output.
      for (ptId=0; ptId < numSourcePts; ptId++)
        {
        id = newPts->InsertNextPoint(sourcePts->GetPoint(ptId));
        outputPD->CopyData(sourcePD, ptId, id);
        }

      for (cellId=0; cellId < numSourceCells; cellId++)
        {
        cell = this->Source->GetCell(cellId);
        cellPts = cell->GetPointIds();
        npts = cellPts->GetNumberOfIds();
        for (pts->Reset(), i=0; i < npts; i++)
          {
          pts->InsertId(i,cellPts->GetId(i) + ptOffset);
          }
        id = output->InsertNextCell(cell->GetCellType(),pts);
        outputCD->CopyData(sourceCD, cellId, id);
        }

      // If we're coloring the output with scalars, do that now
      if ( ptScalars )
        {
        for (ptId=0; ptId < numSourcePts; ptId++)
          {
          idx = (this->ColorMode == VTK_COLOR_BY_INPUT ? this->PointId : ptId);
          ptScalars->InsertNextScalar(inPtScalars->GetScalar(idx));
          }
        }
      else if ( cellScalars )
        {
        for (cellId=0; cellId < numSourceCells; cellId++)
          {
          idx = (this->ColorMode == VTK_COLOR_BY_INPUT ? this->PointId : cellId);
          cellScalars->InsertNextScalar(inCellScalars->GetScalar(idx));
          }
        }

      ptOffset += numSourcePts;

      }//if a source is available
    } //for all input points

  this->Updating = 0;

  pts->Delete();

  output->SetPoints(newPts);
  newPts->Delete();

  if ( ptScalars )
    {
    outputPD->SetScalars(ptScalars);
    ptScalars->Delete();
    }

  if ( cellScalars )
    {
    outputCD->SetScalars(cellScalars);
    cellScalars->Delete();
    }

  output->Squeeze();
}

// Override update method because execution can branch two ways (via Input
// and Source).
void vtkProgrammableGlyphFilter::Update()
{
  // make sure input is available
  if ( this->Input == NULL || this->Source == NULL )
    {
    vtkErrorMacro(<< "No input or source...can't execute!");
    return;
    }

  // prevent chasing our tail
  if (this->Updating) return;

  this->Updating = 1;
  this->Input->Update();
  if ( this->Source ) this->Source->Update();
  this->Updating = 0;

  if (this->Input->GetMTime() > this->ExecuteTime ||
  (this->Source && this->Source->GetMTime() > this->ExecuteTime) ||
  this->GetMTime() > this->ExecuteTime )
    {
    if ( this->Input->GetDataReleased() ) this->Input->ForceUpdate();
    if ( this->Source && this->Source->GetDataReleased() )
      this->Source->ForceUpdate();

    if ( this->StartMethod ) (*this->StartMethod)(this->StartMethodArg);
    this->Output->Initialize(); //clear output
    // reset AbortExecute flag and Progress
    this->AbortExecute = 0;
    this->Progress = 0.0;
    this->Execute();
    this->ExecuteTime.Modified();
    if ( !this->AbortExecute ) this->UpdateProgress(1.0);
    this->SetDataReleased(0);
    if ( this->EndMethod ) (*this->EndMethod)(this->EndMethodArg);
    }

  if ( this->Input->ShouldIReleaseData() ) this->Input->ReleaseData();
  if ( this->Source && this->Source->ShouldIReleaseData() )
    this->Source->ReleaseData();
}

// Specify function to be called before object executes.
void vtkProgrammableGlyphFilter::SetGlyphMethod(void (*f)(void *), void *arg)
{
  if ( f != this->GlyphMethod || arg != this->GlyphMethodArg )
    {
    // delete the current arg if there is one and a delete meth
    if ((this->GlyphMethodArg)&&(this->GlyphMethodArgDelete))
      {
      (*this->GlyphMethodArgDelete)(this->GlyphMethodArg);
      }
    this->GlyphMethod = f;
    this->GlyphMethodArg = arg;
    this->Modified();
    }
}

// Set the arg delete method. This is used to free user memory.
void vtkProgrammableGlyphFilter::SetGlyphMethodArgDelete(void (*f)(void *))
{
  if ( f != this->GlyphMethodArgDelete)
    {
    this->GlyphMethodArgDelete = f;
    this->Modified();
    }
}

// Description:
// Return the method of coloring as a descriptive character string.
char *vtkProgrammableGlyphFilter::GetColorModeAsString(void)
{
  if ( this->ColorMode == VTK_COLOR_BY_INPUT )
    {
    return "ColorByInput";
    }
  else
    {
    return "ColorBySource";
    }
}

void vtkProgrammableGlyphFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkDataSetToPolyDataFilter::PrintSelf(os,indent);

  os << indent << "Source: " << (void *)this->Source << "\n";

  os << indent << "Color Mode: " << this->GetColorModeAsString() << endl;
  os << indent << "Point Id: " << this->PointId << "\n";
  os << indent << "Point: " << this->Point[0]
                    << ", " << this->Point[1]
                    << ", " << this->Point[2] << "\n";
  if (this->PointData)
    {
    os << indent << "PointData: " << this->PointData << "\n";
    }
  else
    {
    os << indent << "PointData: (not defined)\n";
    }

  if ( this->GlyphMethod )
    {
    os << indent << "Glyph Method defined\n";
    }
  else
    {
    os << indent << "No Glyph Method\n";
    }

}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include "src/Options.hpp"
#include "src/Cluster.hpp"

using namespace std;
int main(int argc, char *argv[]){

    cout << argv[0] << endl;
    Options options;

    int n_subdomOnCluster;
    string path2data;

    path2data = "../data/";
    options.set_values(n_subdomOnCluster, path2data);

    if (argc > 1) {
       options.meshSetting.N[0] =  atoi(argv[1]);
    }
    if (argc == 2) {
       options.meshSetting.N[1] =  atoi(argv[2]);
    }
    if (argc == 3) {
       options.meshSetting.N[2] =  atoi(argv[3]);
    }
    if (argc > 4) {
       options.meshSetting.n[0] =  atoi(argv[4]);
    }
    if (argc > 5) {
       options.meshSetting.n[1] =  atoi(argv[5]);
    }
    if (argc > 6) {
       options.meshSetting.n[2] =  atoi(argv[6]);
    }

//    if (argc == 1) {
//       var = atoi(argv[1]);
//    }
//
//    switch (var)
//    {
//        case (0):
//            // small variant: 8 subdom, each 3x3x3 elements
//            n_subdomOnCluster = 8;
//            path2data = "../data/";
//            break;
//        case (1):
//            // larger variant: 27 subdom, each 10x10x10 elements
//            n_subdomOnCluster = 27;
//            path2data = "../data1/";
//            break;
//        case (2):
//            // larger variant: 8 subdom, each 6x6x6 elements
//            n_subdomOnCluster = 8;
//            path2data = "../data2/";
//            break;
//        case (3):
//            // 2nd larger variant: 27 subdom, each 5x5x5 elements
//            n_subdomOnCluster = 27;
//            path2data = "../data3/";
//            break;
//        case (4):
//            // 2nd larger variant: 27 subdom, each 5x5x5 elements
//            // 'kernel' gluing
//            n_subdomOnCluster = 27;
//            path2data = "../data4/";
//            break;
//        case (5):
//            // data are created in application
//            // and 'path2data' is setup for dumped files
//            path2data = "../data5/";
//            break;
//    }

//
    Cluster cluster(options);
    cout << "----------------- done -----------------\n" ;
    return 0;
}
<commit_msg>htfeti.cpp: young modulus and poissons constant can be set up here, part of the code filling mesh parameters passed to Mesh.cpp<commit_after>#include <iostream>
#include <string>
#include "src/Options.hpp"
#include "src/Cluster.hpp"

using namespace std;
int main(int argc, char *argv[]){

    string path2data = "../data/";
/* norm of matrix is mofiedable by 'young_modulus' */
    double young_modulus = 10000;
//    double young_modulus = 2.1e9;
    double poissons_ratio = 0.4999;

/* ---------------------------------------------------------*/
/* ---------------------------------------------------------*/
/* ---------------------------------------------------------*/
/* ---------------------------------------------------------*/

    cout << argv[0] << endl;
    Options options;
    options.set_values(path2data, argc, argv, young_modulus, poissons_ratio);
    Cluster cluster(options);
    cout << "----------------- done -----------------\n" ;
    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/modaloverlay.h>
#include <qt/forms/ui_modaloverlay.h>

#include <qt/guiutil.h>

#include <chainparams.h>

#include <QResizeEvent>
#include <QPropertyAnimation>

ModalOverlay::ModalOverlay(bool enable_wallet, QWidget *parent) :
QWidget(parent),
ui(new Ui::ModalOverlay),
bestHeaderHeight(0),
bestHeaderDate(QDateTime()),
layerIsVisible(false),
userClosed(false)
{
    ui->setupUi(this);
    connect(ui->closeButton, &QPushButton::clicked, this, &ModalOverlay::closeClicked);
    if (parent) {
        parent->installEventFilter(this);
        raise();
    }

    blockProcessTime.clear();
    setVisible(false);
    if (!enable_wallet) {
        ui->infoText->setVisible(false);
        ui->infoTextStrong->setText(tr("Syscoin Core is currently syncing.  It will download headers and blocks from peers and validate them until reaching the tip of the block chain."));
    }
}

ModalOverlay::~ModalOverlay()
{
    delete ui;
}

bool ModalOverlay::eventFilter(QObject * obj, QEvent * ev) {
    if (obj == parent()) {
        if (ev->type() == QEvent::Resize) {
            QResizeEvent * rev = static_cast<QResizeEvent*>(ev);
            resize(rev->size());
            if (!layerIsVisible)
                setGeometry(0, height(), width(), height());

        }
        else if (ev->type() == QEvent::ChildAdded) {
            raise();
        }
    }
    return QWidget::eventFilter(obj, ev);
}

//! Tracks parent widget changes
bool ModalOverlay::event(QEvent* ev) {
    if (ev->type() == QEvent::ParentAboutToChange) {
        if (parent()) parent()->removeEventFilter(this);
    }
    else if (ev->type() == QEvent::ParentChange) {
        if (parent()) {
            parent()->installEventFilter(this);
            raise();
        }
    }
    return QWidget::event(ev);
}

void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate)
{
    if (count > bestHeaderHeight) {
        bestHeaderHeight = count;
        bestHeaderDate = blockDate;
        UpdateHeaderSyncLabel();
    }
}

void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress)
{
    QDateTime currentDate = QDateTime::currentDateTime();

    // keep a vector of samples of verification progress at height
    blockProcessTime.push_front(qMakePair(currentDate.toMSecsSinceEpoch(), nVerificationProgress));

    // show progress speed if we have more than one sample
    if (blockProcessTime.size() >= 2) {
        double progressDelta = 0;
        double progressPerHour = 0;
        qint64 timeDelta = 0;
        qint64 remainingMSecs = 0;
        double remainingProgress = 1.0 - nVerificationProgress;
        for (int i = 1; i < blockProcessTime.size(); i++) {
            QPair<qint64, double> sample = blockProcessTime[i];

            // take first sample after 500 seconds or last available one
            if (sample.first < (currentDate.toMSecsSinceEpoch() - 500 * 1000) || i == blockProcessTime.size() - 1) {
                progressDelta = blockProcessTime[0].second - sample.second;
                timeDelta = blockProcessTime[0].first - sample.first;
                progressPerHour = progressDelta / (double) timeDelta * 1000 * 3600;
                remainingMSecs = (progressDelta > 0) ? remainingProgress / progressDelta * timeDelta : -1;
                break;
            }
        }
        // show progress increase per hour
        ui->progressIncreasePerH->setText(QString::number(progressPerHour * 100, 'f', 2)+"%");

        // show expected remaining time
        if(remainingMSecs >= 0) {
            ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0));
        } else {
            ui->expectedTimeLeft->setText(QObject::tr("unknown"));
        }

        static const int MAX_SAMPLES = 5000;
        if (blockProcessTime.count() > MAX_SAMPLES) {
            blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count() - MAX_SAMPLES);
        }
    }

    // show the last block date
    ui->newestBlockDate->setText(blockDate.toString());

    // show the percentage done according to nVerificationProgress
    ui->percentageProgress->setText(QString::number(nVerificationProgress*100, 'f', 2)+"%");
    ui->progressBar->setValue(nVerificationProgress*100);

    if (!bestHeaderDate.isValid())
        // not syncing
        return;

    // estimate the number of headers left based on nPowTargetSpacing
    // and check if the gui is not aware of the best header (happens rarely)
    int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing;
    bool hasBestHeader = bestHeaderHeight >= count;

    // show remaining number of blocks
    if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {
        ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));
    } else {
        UpdateHeaderSyncLabel();
        ui->expectedTimeLeft->setText(tr("Unknown..."));
    }
}

void ModalOverlay::UpdateHeaderSyncLabel() {
    int est_headers_left = bestHeaderDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
    ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1, %2%)...").arg(bestHeaderHeight).arg(QString::number(100.0 / (bestHeaderHeight + est_headers_left) * bestHeaderHeight, 'f', 1)));
}

void ModalOverlay::toggleVisibility()
{
    showHide(layerIsVisible, true);
    if (!layerIsVisible)
        userClosed = true;
}

void ModalOverlay::showHide(bool hide, bool userRequested)
{
    if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested))
        return;

    if (!isVisible() && !hide)
        setVisible(true);

    setGeometry(0, hide ? 0 : height(), width(), height());

    QPropertyAnimation* animation = new QPropertyAnimation(this, "pos");
    animation->setDuration(300);
    animation->setStartValue(QPoint(0, hide ? 0 : this->height()));
    animation->setEndValue(QPoint(0, hide ? this->height() : 0));
    animation->setEasingCurve(QEasingCurve::OutQuad);
    animation->start(QAbstractAnimation::DeleteWhenStopped);
    layerIsVisible = !hide;
}

void ModalOverlay::closeClicked()
{
    showHide(true);
    userClosed = true;
}
<commit_msg>GUI: Use PACKAGE_NAME in modal overlay<commit_after>// Copyright (c) 2016-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/modaloverlay.h>
#include <qt/forms/ui_modaloverlay.h>

#include <qt/guiutil.h>

#include <chainparams.h>

#include <QResizeEvent>
#include <QPropertyAnimation>

ModalOverlay::ModalOverlay(bool enable_wallet, QWidget *parent) :
QWidget(parent),
ui(new Ui::ModalOverlay),
bestHeaderHeight(0),
bestHeaderDate(QDateTime()),
layerIsVisible(false),
userClosed(false)
{
    ui->setupUi(this);
    connect(ui->closeButton, &QPushButton::clicked, this, &ModalOverlay::closeClicked);
    if (parent) {
        parent->installEventFilter(this);
        raise();
    }

    blockProcessTime.clear();
    setVisible(false);
    if (!enable_wallet) {
        ui->infoText->setVisible(false);
        ui->infoTextStrong->setText(tr("%1 is currently syncing.  It will download headers and blocks from peers and validate them until reaching the tip of the block chain.").arg(PACKAGE_NAME));
    }
}

ModalOverlay::~ModalOverlay()
{
    delete ui;
}

bool ModalOverlay::eventFilter(QObject * obj, QEvent * ev) {
    if (obj == parent()) {
        if (ev->type() == QEvent::Resize) {
            QResizeEvent * rev = static_cast<QResizeEvent*>(ev);
            resize(rev->size());
            if (!layerIsVisible)
                setGeometry(0, height(), width(), height());

        }
        else if (ev->type() == QEvent::ChildAdded) {
            raise();
        }
    }
    return QWidget::eventFilter(obj, ev);
}

//! Tracks parent widget changes
bool ModalOverlay::event(QEvent* ev) {
    if (ev->type() == QEvent::ParentAboutToChange) {
        if (parent()) parent()->removeEventFilter(this);
    }
    else if (ev->type() == QEvent::ParentChange) {
        if (parent()) {
            parent()->installEventFilter(this);
            raise();
        }
    }
    return QWidget::event(ev);
}

void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate)
{
    if (count > bestHeaderHeight) {
        bestHeaderHeight = count;
        bestHeaderDate = blockDate;
        UpdateHeaderSyncLabel();
    }
}

void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress)
{
    QDateTime currentDate = QDateTime::currentDateTime();

    // keep a vector of samples of verification progress at height
    blockProcessTime.push_front(qMakePair(currentDate.toMSecsSinceEpoch(), nVerificationProgress));

    // show progress speed if we have more than one sample
    if (blockProcessTime.size() >= 2) {
        double progressDelta = 0;
        double progressPerHour = 0;
        qint64 timeDelta = 0;
        qint64 remainingMSecs = 0;
        double remainingProgress = 1.0 - nVerificationProgress;
        for (int i = 1; i < blockProcessTime.size(); i++) {
            QPair<qint64, double> sample = blockProcessTime[i];

            // take first sample after 500 seconds or last available one
            if (sample.first < (currentDate.toMSecsSinceEpoch() - 500 * 1000) || i == blockProcessTime.size() - 1) {
                progressDelta = blockProcessTime[0].second - sample.second;
                timeDelta = blockProcessTime[0].first - sample.first;
                progressPerHour = progressDelta / (double) timeDelta * 1000 * 3600;
                remainingMSecs = (progressDelta > 0) ? remainingProgress / progressDelta * timeDelta : -1;
                break;
            }
        }
        // show progress increase per hour
        ui->progressIncreasePerH->setText(QString::number(progressPerHour * 100, 'f', 2)+"%");

        // show expected remaining time
        if(remainingMSecs >= 0) {
            ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0));
        } else {
            ui->expectedTimeLeft->setText(QObject::tr("unknown"));
        }

        static const int MAX_SAMPLES = 5000;
        if (blockProcessTime.count() > MAX_SAMPLES) {
            blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count() - MAX_SAMPLES);
        }
    }

    // show the last block date
    ui->newestBlockDate->setText(blockDate.toString());

    // show the percentage done according to nVerificationProgress
    ui->percentageProgress->setText(QString::number(nVerificationProgress*100, 'f', 2)+"%");
    ui->progressBar->setValue(nVerificationProgress*100);

    if (!bestHeaderDate.isValid())
        // not syncing
        return;

    // estimate the number of headers left based on nPowTargetSpacing
    // and check if the gui is not aware of the best header (happens rarely)
    int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing;
    bool hasBestHeader = bestHeaderHeight >= count;

    // show remaining number of blocks
    if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {
        ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));
    } else {
        UpdateHeaderSyncLabel();
        ui->expectedTimeLeft->setText(tr("Unknown..."));
    }
}

void ModalOverlay::UpdateHeaderSyncLabel() {
    int est_headers_left = bestHeaderDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
    ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1, %2%)...").arg(bestHeaderHeight).arg(QString::number(100.0 / (bestHeaderHeight + est_headers_left) * bestHeaderHeight, 'f', 1)));
}

void ModalOverlay::toggleVisibility()
{
    showHide(layerIsVisible, true);
    if (!layerIsVisible)
        userClosed = true;
}

void ModalOverlay::showHide(bool hide, bool userRequested)
{
    if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested))
        return;

    if (!isVisible() && !hide)
        setVisible(true);

    setGeometry(0, hide ? 0 : height(), width(), height());

    QPropertyAnimation* animation = new QPropertyAnimation(this, "pos");
    animation->setDuration(300);
    animation->setStartValue(QPoint(0, hide ? 0 : this->height()));
    animation->setEndValue(QPoint(0, hide ? this->height() : 0));
    animation->setEasingCurve(QEasingCurve::OutQuad);
    animation->start(QAbstractAnimation::DeleteWhenStopped);
    layerIsVisible = !hide;
}

void ModalOverlay::closeClicked()
{
    showHide(true);
    userClosed = true;
}
<|endoftext|>