From f8c7213bb9bde9f6c25a705d4ac6c1ea3059f73f Mon Sep 17 00:00:00 2001 From: Oleksandr Nahnybida Date: Wed, 30 Aug 2023 22:48:10 +0300 Subject: [PATCH] Redirect program output to separate window --- gf2.cpp | 10 ++++++++++ windows.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/gf2.cpp b/gf2.cpp index 8d5c3d1..e7e45a2 100644 --- a/gf2.cpp +++ b/gf2.cpp @@ -22,6 +22,7 @@ #include #include #include +#include extern "C" { #define UI_FONT_PATH @@ -33,6 +34,7 @@ extern "C" { #define MSG_RECEIVED_DATA ((UIMessage) (UI_MSG_USER + 1)) #define MSG_RECEIVED_CONTROL ((UIMessage) (UI_MSG_USER + 2)) #define MSG_RECEIVED_LOG ((UIMessage) (UI_MSG_USER + 3)) +#define MSG_RECEIVED_STDOUT ((UIMessage) (UI_MSG_USER + 4)) // Data structures: @@ -142,6 +144,9 @@ FILE *commandLog; char emptyString; bool programRunning = true; const char *vimServerName = "GVIM"; + +char setPttyCMD[PATH_MAX]; +int pseudoTerminalMasterFD = -1; const char *logPipePath; const char *controlPipePath; Array presetCommands; @@ -558,6 +563,8 @@ void *DebuggerThread(void *) { const char *setPrompt = "set prompt (gdb) \n"; write(pipeToGDB, setPrompt, strlen(setPrompt)); + write(pipeToGDB, setPttyCMD, strlen(setPttyCMD)); + char *catBuffer = NULL; size_t catBufferUsed = 0; size_t catBufferAllocated = 0; @@ -1310,6 +1317,7 @@ void InterfaceAddBuiltinWindowsAndCommands() { interfaceWindows.Add({ "Files", FilesWindowCreate, nullptr }); interfaceWindows.Add({ "Console", ConsoleWindowCreate, nullptr }); interfaceWindows.Add({ "Log", LogWindowCreate, nullptr }); + interfaceWindows.Add({ "STDOUT", STDOUTWindowCreate, nullptr }); interfaceWindows.Add({ "Thread", ThreadWindowCreate, ThreadWindowUpdate }); interfaceWindows.Add({ "Exe", ExecutableWindowCreate, nullptr }); @@ -1482,6 +1490,8 @@ int WindowMessage(UIElement *, UIMessage message, int di, void *dp) { free(input); } else if (message == MSG_RECEIVED_LOG) { LogReceived(dp); + } else if (message == MSG_RECEIVED_STDOUT) { + STDOUTReceived(dp); } else if (message == UI_MSG_WINDOW_ACTIVATE) { DisplaySetPosition(currentFileFull, currentLine, false); } diff --git a/windows.cpp b/windows.cpp index 81bfabb..050cf8a 100644 --- a/windows.cpp +++ b/windows.cpp @@ -2521,6 +2521,63 @@ UIElement *CommandsWindowCreate(UIElement *parent) { return &panel->e; } +////////////////////////////////////////////////////// +// STDOUT window: +////////////////////////////////////////////////////// + +void *STDOUTWindowThread(void *context) { + if (pseudoTerminalMasterFD < 0) { + fprintf(stderr, "Warning: ptty fd invalid\n"); + return nullptr; + } + + struct pollfd p = { .fd = pseudoTerminalMasterFD, .events = POLLIN }; + + while (true) { + poll(&p, 1, 10000); + + if (p.revents & POLLHUP) { + struct timespec t = { .tv_nsec = 10000000 }; + nanosleep(&t, 0); + } + + while (true) { + char input[16384]; + int length = read(pseudoTerminalMasterFD, input, sizeof(input) - 1); + if (length <= 0) break; + input[length] = 0; + void *buffer = malloc(strlen(input) + sizeof(context) + 1); + memcpy(buffer, &context, sizeof(context)); + strcpy((char *) buffer + sizeof(context), input); + UIWindowPostMessage(windowMain, MSG_RECEIVED_STDOUT, buffer); + } + } +} + +void STDOUTReceived(void *buffer) { + UICodeInsertContent(*(UICode **) buffer, (char *) buffer + sizeof(void *), -1, false); + UIElementRefresh(*(UIElement **) buffer); + free(buffer); +} + +UIElement *STDOUTWindowCreate(UIElement *parent) { + int master_tty, slave_tty; + char pseudoTerminalPath[PATH_MAX]; + int ret = openpty(&master_tty, &slave_tty, pseudoTerminalPath, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "Warning: cannot open pseudo tty"); + /* TODO(Oleksandr): What should I do here, is it allowed to return NULL from window create? */ + } + StringFormat(setPttyCMD, sizeof(setPttyCMD), "tty %s\n", pseudoTerminalPath); + pseudoTerminalMasterFD = master_tty; + + + UICode *code = UICodeCreate(parent, 0); + pthread_t thread; + pthread_create(&thread, nullptr, STDOUTWindowThread, code); + return &code->e; +} + ////////////////////////////////////////////////////// // Log window: //////////////////////////////////////////////////////