diff --git a/qtest.pro b/qtest.pro index ba2c13e..be04829 100644 --- a/qtest.pro +++ b/qtest.pro @@ -1,8 +1,8 @@ -QMAKE_CXXFLAGS += --target=x86_64-w64-mingw32 -g -gcodeview -O0 -Werror=return-type +QMAKE_CXXFLAGS += --target=x86_64-w64-mingw32 -g -gcodeview -O0 -Werror=return-type QMAKE_LFLAGS += --target=x86_64-w64-mingw32 -g -Wl,-pdb= -v LIBS += -LC:/capybara/libclang/x86_64-w64-mingw32/lib -lWinmm -lodbc32 -lodbccp32 -luuid -loleaut32 -lole32 -lshell32 -ladvapi32 -lcomdlg32 -lwinspool -lgdi32 -luser32 -lkernel32 -lpropsys -static -stdlib=libc++ -lunwind #"kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" -luuid -loleaut32 -lole32 -lshell32 -ladvapi32 -lcomdlg32 -lwinspool -lgdi32 -luser32 -lkernel32 -DEFINES += DEBUG QT_LOGGING_TO_CONSOLE=1 WIN32_LEAN_AND_MEAN +DEFINES += DEBUG QT_LOGGING_TO_CONSOLE=1 WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602 CONFIG += debug QT += widgets network @@ -10,8 +10,8 @@ INCLUDEPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\back\reimp DESTPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\back\reimpl" "$$PWD\src\cont" VPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\back\reimpl" "$$PWD\src\cont" -SOURCES += qtestmain.cpp qtclasses.cpp backlasses.cpp backsessionclasses.cpp contclasses.cpp contsessionclasses.cpp -HEADERS += qtclasses.h backlasses.h backsessionclasses.h contclasses.h contsessionclasses.h global.h debug.h backfuncs.h ipolicyconfig.h msinclude.h meterslider.h qtvisuals.h +SOURCES += qtestmain.cpp qtclasses.cpp backlasses.cpp backsessionclasses.cpp contclasses.cpp contsessionclasses.cpp settings.cpp +HEADERS += qtclasses.h backlasses.h backsessionclasses.h contclasses.h contsessionclasses.h global.h debug.h backfuncs.h ipolicyconfig.h msinclude.h meterslider.h qtvisuals.h settings.h RESOURCES = assets.qrc RC_ICONS += assets/logo.ico diff --git a/src/back/backsessionclasses.h b/src/back/backsessionclasses.h index 3f73f3d..ae87f0a 100644 --- a/src/back/backsessionclasses.h +++ b/src/back/backsessionclasses.h @@ -4,7 +4,6 @@ #include "global.h" #include "contclasses.h" -#include class Endpoint; class SessionStateCallback : public IAudioSessionEvents { diff --git a/src/back/msinclude.h b/src/back/msinclude.h index f9ab1b4..633e079 100644 --- a/src/back/msinclude.h +++ b/src/back/msinclude.h @@ -1,7 +1,5 @@ #pragma once -#define _WIN32_WINNT 0x0A00 - #include //done by qt by def #define UNICODE @@ -9,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -28,6 +28,7 @@ #include #include #include +#include #include "ipolicyconfig.h" #include "audiometerinfo.h" diff --git a/src/global.h b/src/global.h index 4d684a9..10f45ab 100644 --- a/src/global.h +++ b/src/global.h @@ -10,8 +10,10 @@ #include #include #include +#include #include "debug.h" +//#include "settings.h" //TODO: Use tr();? QTranslator #define STRING_MUTE "Mute" @@ -30,12 +32,17 @@ #define STRING_CP "Open Control Panel" #define STRING_ABOUT "About" #define STRING_STARTUP "Run at startup" +#define STRING_CHANNELS "Show endpoint channels" #define STRING_NOENDPOINT "No active endpoints" #define LSTRING_UNNAMED_SESSION L"Unnamed session" + + //INIT BACK + + enum ProcessedNativeEvent { NONE = 0, COLORS = (1 << 0), @@ -92,7 +99,11 @@ struct NGuid { /* }while (i < 8); */ /* } */ }; +namespace ini { + class UserSettings; +} +extern ini::UserSettings *set; class OverseerHandler; extern OverseerHandler *osh; diff --git a/src/qt/qtclasses.cpp b/src/qt/qtclasses.cpp index 78d99f0..86c9a22 100644 --- a/src/qt/qtclasses.cpp +++ b/src/qt/qtclasses.cpp @@ -296,7 +296,7 @@ void MainWindow::compose() { this->mainMenuBar->setMaximumWidth((int)windowWidth); for (auto *epw : ews) { if (!epw) continue; - + epw->updateChannelsVisibility(); epw->calculateSize(windowWidth - scrollArea->verticalScrollBar()->sizeHint().width() - widgetLayout->contentsMargins().left() , screenHeight); @@ -605,8 +605,12 @@ EndpointWidget::EndpointWidget(EndpointHandler* eph, QWidget *parent, uint64_t i if(epChannelCount > 1) { cw = new ChannelWidget(epChannelCount, eph, nullptr); cw->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - //cw->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); widgetLayout->addWidget(cw, row++, 0, 1, 4 /*colmax*/, Qt::AlignTop); + cw->setVisible(false); + char* const channelSettings = set->getValue("show_channels"); + if(channelSettings && !(strcmp(channelSettings, "true"))){ + cw->setVisible(true); + } } /* @@ -889,6 +893,13 @@ void EndpointWidget::updateMainVolume(int newValue){ * } */ +void EndpointWidget::updateChannelsVisibility() { + char* const channelSettings = set->getValue("show_channels"); + if(channelSettings && !(strcmp(channelSettings, "true"))){ + cw->setVisible(true); + } else cw->setVisible(false); +} + EndpointHandler* EndpointWidget::getEndpointHandler(){ return this->eph; } @@ -915,19 +926,36 @@ std::map EndpointWidget::getDefaultRolesWidgets() { HeaderWidget::HeaderWidget(QWidget *parent) : QWidget(parent) { widgetLayout = new QGridLayout(this); - QString text = "&" STRING_ABOUT; - about = new QPushButton(text, this); + QString text; //= "&" STRING_ABOUT; + //about = new QPushButton(text, this); #ifdef WIN32 text = "&" STRING_CP; openCP = new QPushButton(text, this); connect(openCP, &QPushButton::clicked, [](){ osh->openControlPanel(); }); - text = "&" STRING_STARTUP; - startup = new QPushButton(text, this); + + text = "&" STRING_CHANNELS; + channels = new QCheckBox(text, this); + char* const channelSettings = set->getValue("show_channels"); + if(channelSettings && !(strcmp(channelSettings, "true"))){ + channels->setChecked(true); + } + connect(channels, &QCheckBox::stateChanged, [this, parent](){ + set->setValue("show_channels", channels->isChecked(), sizeof("show_channels")); + if(parent) + QCoreApplication::instance()->postEvent + (parent, new QEvent((QEvent::Type)CustomQEvent::RecomposeMainWindow)); + }); - widgetLayout->addWidget(openCP , 0, 0); - widgetLayout->addWidget(startup, 0, 1); + + text = "&" STRING_STARTUP; + startup = new QCheckBox(text, this); + //connect(openCP, &QPushButton::clicked, [](){ osh->openControlPanel(); }); + + widgetLayout->addWidget(openCP , 0, 0, 2, 2); + widgetLayout->addWidget(channels, 0, 2, 1, 2); + widgetLayout->addWidget(startup , 1, 2, 1, 2); #endif - widgetLayout->addWidget(about , 0, 2); + //widgetLayout->addWidget(about , 0, 2); this->setLayout(widgetLayout); } @@ -1034,19 +1062,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { * Menu bar code */ mainMenuBar = new QToolBar(this); - /* - * QPalette pal; - * pal.setColor(QPalette::Window, Qt::transparent); - * mainMenuBar->setPalette(pal); - */ hw = new HeaderWidget(this); mainMenuBar->addWidget(hw); mainMenuBar->setMovable(false); this->addToolBar(Qt::BottomToolBarArea, mainMenuBar); reloadEndpointWidgets(); - //scrollArea->setMinimumWidth(ews.at(0)->minimumWidth()); - log_debugcpp(std::to_string(scrollArea->minimumWidth())); /* * Tray Icon code diff --git a/src/qt/qtclasses.h b/src/qt/qtclasses.h index 36a0add..5531921 100644 --- a/src/qt/qtclasses.h +++ b/src/qt/qtclasses.h @@ -2,6 +2,7 @@ #include "qtcommon.h" #include "contclasses.h" +#include "settings.h" class MeterSlider; @@ -100,7 +101,7 @@ public: EndpointWidget(EndpointHandler* eph, QWidget *parent = nullptr, uint64_t idx = INT_MAX); //QSize minimumSizeHint() const override; //void setMinimum(uint64_t height, double heightRatio); - + void updateChannelsVisibility(); EndpointHandler* getEndpointHandler(); std::map getDefaultRolesWidgets(); @@ -167,10 +168,11 @@ public: private: QGridLayout *widgetLayout; - QPushButton *about; + //QPushButton *about; #ifdef WIN32 QPushButton *openCP; - QPushButton *startup; + QCheckBox *startup; + QCheckBox *channels; #endif }; diff --git a/src/qtestmain.cpp b/src/qtestmain.cpp index 387df74..e367ae9 100644 --- a/src/qtestmain.cpp +++ b/src/qtestmain.cpp @@ -3,9 +3,11 @@ #include "qtcommon.h" #include "qtclasses.h" #include "qtvisuals.h" +#include "settings.h" //#include "global.h" -OverseerHandler *osh = nullptr; +OverseerHandler *osh = nullptr; +ini::UserSettings *set = nullptr; QApplication* createApplication(int &argc, char *argv[]) { @@ -31,6 +33,14 @@ void closeDebugFileLog() { close_file_log_buffer(); } +char* parseCmdArgs(int argc, char* argv[]) { + if(argc == 1) return nullptr; + char arg[] = "--config-path="; + if(strstr(argv[1], arg)) { + return argv[1] + (sizeof(arg) / sizeof(arg[0])) - 1; + } else return nullptr; +} + /* set_terminate * void closeDebugFileLog2() { * close_file_log_buffer(); @@ -46,6 +56,8 @@ int main (int argc, char* argv[]) { * log_debugcpp(a.toStdString()); * } */ + //std::map* values = new std::map{ {"show_channels", false}, {"test", 7} }; + set = new ini::UserSettings(parseCmdArgs(argc, argv)); initialize_file_log(); atexit(closeDebugFileLog); diff --git a/src/settings.cpp b/src/settings.cpp new file mode 100644 index 0000000..0ced9fd --- /dev/null +++ b/src/settings.cpp @@ -0,0 +1,208 @@ +#include "settings.h" +#include "msinclude.h" + +namespace ini { + + UserSettings::UserSettings(char* path) { + wchar_t* settingsPath = nullptr; + wchar_t settingsFile[] = L"\\settings.ini"; + uint32_t settingsFileLen = (sizeof(settingsFile) / sizeof(wchar_t)) - 1; + wchar_t maxPathBypass[] = L"\\\\?\\"; + log_wdebugcpp(L"Bypass size: " + std::to_wstring((sizeof(maxPathBypass)/sizeof(maxPathBypass[0])))); + + //Executable dir + settingsPath = (wchar_t*)calloc(UNICODE_STRING_MAX_CHARS, sizeof(wchar_t)); + uint32_t exePathLength = GetModuleFileNameW( + NULL, + settingsPath, + UNICODE_STRING_MAX_CHARS + ); + //reverse wcsstr + while(exePathLength >= 0) { + if(settingsPath[exePathLength] == '\\') { + memset(settingsPath + exePathLength, + 0, + (UNICODE_STRING_MAX_CHARS - exePathLength) * sizeof(wchar_t)); + break; + } else exePathLength--; + } + log_wdebugcpp(L"Exe folder: " + std::wstring(settingsPath)); + + HANDLE settingsHandle = nullptr; + if((UNICODE_STRING_MAX_CHARS - exePathLength) > (settingsFileLen + 1)) { + memcpy(settingsPath + exePathLength, settingsFile, sizeof(wchar_t) * settingsFileLen); + settingsHandle = CreateFile2( + settingsPath, + GENERIC_READ | GENERIC_WRITE, + 0, + OPEN_ALWAYS, + NULL); + if(settingsHandle != INVALID_HANDLE_VALUE) { log_debugcpp("Filecreated!"); } + else { CloseHandle(settingsHandle); settingsHandle = nullptr; return; } + } + + //Calculating file size and reading file + if(settingsHandle) { + uint64_t fileSize; + LARGE_INTEGER fileSizeStruct; + if(!GetFileSizeEx(settingsHandle, &fileSizeStruct)) return; + fileSize = fileSizeStruct.QuadPart; + + uint32_t bytesRead = 0; + textContentsSize = fileSize + 1; + textContents = (char*)calloc(textContentsSize, sizeof(char)); + if (ReadFile(settingsHandle, textContents, fileSize, + (LPDWORD)&bytesRead, NULL) != TRUE) { + free(textContents); + return; + } + //textContents.assign(tempTextContents); + //free(tempTextContents); + + //Parsing values + bool isCRLF = false; + char *curLine = textContents; + char *separator = nullptr, *key = nullptr, *value = nullptr; + while(curLine) { + char* nextLine = strchr(curLine, '\n'); + if(nextLine == curLine + 1 || nextLine == curLine + 2) goto nextIteration; + if (nextLine && (isCRLF || *(nextLine - 1) == '\r')) { + isCRLF = true; + *(nextLine - 1) = '\0'; + } else if (nextLine) *nextLine = '\0'; // temporarily terminate the current line + log_debugcpp("curLine: " + std::string(curLine) + " "); + + separator = strchr(curLine, '='); + if(!separator) goto nextIteration; + *separator = '\0'; + key = trimAndAllocate(curLine); + value = trimAndAllocate(separator + 1); + values.try_emplace(key, value); + log_debugcpp("ini Map size: " + std::to_string(values.size())); + *separator = '='; + + nextIteration: + if (nextLine) { // then restore newline-char, just to be tidy + if (isCRLF) + *(nextLine - 1) = '\r'; + else *nextLine = '\n'; + } + curLine = nextLine ? (nextLine + 1) : NULL; + } + /* + * for(const std::pair keyVal : defaultValues) { + * if (textContents.find(keyVal.first) { + * if (keyVal. + * } + * } + */ + } + } + + //todo: buffer overflow. poc + char* const UserSettings::getValue(char* key, uint64_t len) { + if (auto search = values.find(key); search != values.end()) + return (char* const) search->second; + return nullptr; + } + + void UserSettings::setValue(char* key, char* value, uint64_t valueSize, uint64_t keySize) { + char *newValue, *newKey; + if (auto search = values.find(key); search != values.end()) { + if(!(strcmp(value, search->second))) return; + newValue = (char*)calloc(valueSize, sizeof(char)); + if (!(search->second == pos || search->second == neg)) { + free(search->second); + } + search->second = newValue; + return; + } + + newValue = (char*)calloc(valueSize, sizeof(char)); + newKey = (char*)calloc(keySize, sizeof(char)); + values.insert(std::make_pair(newKey, newValue)); + return; + } + + void UserSettings::setValue(char* key, bool value, uint64_t keySize) { + char *newKey; + log_debugcpp("Pos value: " + std::to_string((intptr_t)pos)); + log_debugcpp("Neg value: " + std::to_string((intptr_t)neg)); + if (auto search = values.find(key); search != values.end()) { + log_debugcpp("Previous value: " + std::to_string((intptr_t)values[key])); + if (!(search->second == pos || search->second == neg)) { + free(search->second); + } + if (value) + search->second = pos; + else search->second = neg; + return; + } + + newKey = (char*)calloc(keySize, sizeof(char)); + values.insert(std::make_pair(newKey, value ? pos : neg)); + return; + } + + + + //AppData path + /* + * wchar_t folderPath[] = L"\\mixerq"; + * + * wchar_t* roamingPath = nullptr; + * if(SHGetKnownFolderPath( + * FOLDERID_RoamingAppData, + * 0, + * NULL, + * &roamingPath) + * == S_OK) { + * uint32_t pathLen = 0; + * wchar_t currentChar = roamingPath[pathLen]; + * while(currentChar != '\0') { + * pathLen++; + * currentChar = roamingPath[pathLen]; + * } + * + * uint32_t maxPathBypassLen = (sizeof(maxPathBypass)/ sizeof(wchar_t)) - 1; + * uint32_t folderPathLen = (sizeof(folderPath) / sizeof(wchar_t)) - 1; + * settingsPath = (wchar_t*)calloc(pathLen + + * maxPathBypassLen + + * folderPathLen + + * settingsFileLen, + * sizeof(wchar_t)); + * memcpy(settingsPath, maxPathBypass, sizeof(wchar_t) * maxPathBypassLen); + * memcpy(settingsPath + (maxPathBypassLen), roamingPath, sizeof(wchar_t) * pathLen); + * CoTaskMemFree(roamingPath); + * memcpy(settingsPath + (maxPathBypassLen + pathLen), + * folderPath, sizeof(wchar_t) * folderPathLen); + * log_wdebugcpp(L"Settings folder path: " + std::wstring(settingsPath)); + * + * if(CreateDirectoryW(settingsPath, NULL) || GetLastError() == ERROR_ALREADY_EXISTS) { + * memcpy(settingsPath + (maxPathBypassLen + pathLen + folderPathLen), + * settingsFile, sizeof(wchar_t) * settingsFileLen); + * + * HANDLE settingsHandle = CreateFile2( + * settingsPath, + * GENERIC_READ | GENERIC_WRITE, + * 0, + * OPEN_ALWAYS, + * NULL); + * if(settingsHandle != INVALID_HANDLE_VALUE) log_debugcpp("Filecreated!"); + * + * } + * //End AppData + */ + + + +UserSettings::~UserSettings() { + if(textContents) free(textContents); + for(std::pair entry : values) { + free(entry.first); + free(entry.second); + } +} + + +} diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 0000000..2e88598 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,75 @@ +#pragma once +#include "global.h" + +namespace ini { + + //Trims spaces, LF and CRLF + static inline char* trimAndAllocate(const char* in, uint64_t len = 0) { + if (!in) return nullptr; + + uint64_t startingPos = 0, lastPos = 0; + bool foundStart = false; + for(int i = 0; ;i++) { + char c = in[i]; + if ((len > 0 && startingPos == (len - 1)) || (len > 0 && lastPos == (len - 1))) return nullptr; + if ((c != ' ' || c != '\r' || c != '\n') && !foundStart) { + foundStart = true; + lastPos = startingPos; + } + if (foundStart && (c == ' ' || c == '\r' || c == '\n')) { + break; + } + if(!foundStart) + startingPos++; + else lastPos++; + } + if(!(lastPos - startingPos)) return nullptr; + + char* trimmedString = (char*)calloc(lastPos - startingPos + 1, sizeof(char)); + memcpy(trimmedString, in + startingPos, lastPos - startingPos); + return trimmedString; + } + + struct Djb12Hasher { + size_t operator()(char* str) const { + unsigned long hash = 5381; + int c; + + while (c = *str++) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + + return hash; + } + }; + + struct StrcmpEqual { + bool operator()(char* key1, char* key2) const { + return (!strcmp(key1, key2)); + } + }; + +class UserSettings { + + public: + UserSettings(char* path = nullptr); + ~UserSettings(); + + char* const getValue(char* key, uint64_t len = 0); + void setValue(char* key, char* value, uint64_t valueSize, uint64_t keySize); //'\0' included + void setValue(char* key, bool value, uint64_t keySize); //'\0' included + //void setValue(char* key, uint64_t value, uint64_t valueSize, uint64_t keySize); //'\0' included + + protected: + + private: + //void* returnValue(); + + //std::map values{ {"show_channels", false}, {"test", 7} }; + std::unordered_map values; + char* textContents = nullptr; + uint64_t textContentsSize = 0; + char* pos = "true"; + char* neg = "false"; +}; + +}