diff --git a/src/back/backlasses.cpp b/src/back/backlasses.cpp index cf5700b..e0238c7 100644 --- a/src/back/backlasses.cpp +++ b/src/back/backlasses.cpp @@ -1,7 +1,19 @@ #include "backlasses.h" #include "backfuncs.h" -std::string getPath(SettingsTargetDirectory target, bool create) { +using namespace Environment; + +wchar_t* getExeAbsPath(uint32_t *exeAbsPathLength) { + wchar_t *exeAbsPath = (wchar_t*)calloc(UNICODE_STRING_MAX_CHARS, sizeof(wchar_t)); + *exeAbsPathLength = GetModuleFileNameW( + NULL, + exeAbsPath, + UNICODE_STRING_MAX_CHARS + ); + return exeAbsPath; +} + +std::string getSettingsPath(SettingsTargetDirectory target, bool create) { wchar_t* settingsPath = nullptr; wchar_t settingsFile[] = L"\\settings.ini"; uint32_t settingsFileLen = (sizeof(settingsFile) / sizeof(wchar_t)) - 1; @@ -57,12 +69,8 @@ std::string getPath(SettingsTargetDirectory target, bool create) { case APP_PATH: { //Executable dir - settingsPath = (wchar_t*)calloc(UNICODE_STRING_MAX_CHARS, sizeof(wchar_t)); - exePathLength = GetModuleFileNameW( - NULL, - settingsPath, - UNICODE_STRING_MAX_CHARS - ); + settingsPath = getExeAbsPath(&exePathLength); + //reverse wcsstr while(exePathLength >= 0) { if(settingsPath[exePathLength] == '\\') { @@ -730,8 +738,23 @@ Endpoint* Overseer::addEndpoint(std::wstring endpointId, /* out */Flows* flow = } Overseer::Overseer() : epsc(this){ - //Initializing COM library log_debugcpp("Initializing Overseer"); + + //Storing exe path for later use (mainly "Run on startup") + log_debugcpp("-Caching exe path"); + uint32_t cPathLen = 0; + wchar_t* cPath = getExeAbsPath(&cPathLen); + exeAbsPath = cPath; + + //Detecting install scope + wchar_t *machine = wcsstr(cPath, L"Program Files"); + if (!machine) + Environment::scope = HKEY_CURRENT_USER; + else Environment::scope = HKEY_LOCAL_MACHINE; + free(cPath); + + //Initializing COM library + log_debugcpp("-Initializing COM"); initCOMLibrary(); //Obtaining playback endpoint collection on this point in time @@ -744,11 +767,44 @@ Overseer::Overseer() : epsc(this){ if(FAILED(deviceEnumerator->RegisterEndpointNotificationCallback(((IMMNotificationClient*)&epsc)))) { log_debugcpp("when no enchufas......"); } } -void Overseer::populateSystemValues() { - updateColors(); +NGuid Overseer::getGuid() { + return guid; } -void Overseer::openControlPanel() { +std::vector Overseer::getPlaybackEndpoints() { + return playbackDevices; +} + +std::vector Overseer::getCaptureEndpoints() { + return captureDevices; +} + +void Overseer::updateEndpointInfo(std::wstring endpointId) { + log_wdebugcpp(L"new name Endpoint id: " + endpointId); + //todo: reintroduce capture devices + for(auto ep : playbackDevices) { + if (ep->getId() == endpointId) { + ep->updateName(); + osh->updateFrontEndpointName(ep); + break; + } + } +} + +Overseer::~Overseer(){ + log_debugcpp("cum"); + deviceEnumerator->Release(); + for(unsigned long long i = 0; i < playbackDevices.size(); i++){ + delete(playbackDevices.at(i)); + } +} + +void Environment::populateSystemValues() { + updateColors(); + Environment::startup = checkStartup(scope); +} + +void Environment::openControlPanel() { STARTUPINFOEXW startupConfig; PROCESS_INFORMATION processInfo; SecureZeroMemory(&startupConfig, sizeof(STARTUPINFOEXW)); @@ -774,7 +830,7 @@ void Overseer::openControlPanel() { } } -ProcessedNativeEvent Overseer::processTopLevelWindowMessage(void* msg) { +ProcessedNativeEvent Environment::processTopLevelWindowMessage(void* msg) { #ifdef WIN32 MSG *message = static_cast(msg); switch(message->message) { @@ -792,7 +848,7 @@ ProcessedNativeEvent Overseer::processTopLevelWindowMessage(void* msg) { #endif } -ProcessedNativeEvent Overseer::updateColors() { +ProcessedNativeEvent Environment::updateColors() { // DwmGetColorizationColor( WM_DWMCOLORIZATIONCOLORCHANGED DWORD value = 0; DWORD size = sizeof(DWORD); @@ -801,57 +857,119 @@ ProcessedNativeEvent Overseer::updateColors() { //Theme bg color result = RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", L"AppsUseLightTheme", RRF_RT_REG_DWORD, nullptr, &value, &size); - - this->lightMode = (bool)value; + lightMode = (bool)value; //Accent color result = RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\DWM", L"ColorizationColor", RRF_RT_REG_DWORD, nullptr, &value, &size); - if (result == ERROR_SUCCESS) { - this->accentColor = value; - } else this->accentColor = 0xffffffff; + accentColor = value; + } else accentColor = 0xffffffff; return ProcessedNativeEvent::COLORS; } -bool Overseer::isLightMode() { - return this->lightMode; +bool Environment::checkStartup(HKEY rootKeyFlags) { + //LSTATUS result; + DWORD typeReturned; + + //Checking if app entry exists + if(RegGetValueW(rootKeyFlags, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", LAPP_NAME, RRF_RT_REG_SZ, &typeReturned, nullptr, nullptr) != ERROR_SUCCESS && typeReturned != REG_SZ) + return false; + else return true; } -uint32_t Overseer::getAccentColor() { - return this->accentColor; -} +void Environment::updateStartupConfig(bool onStartup) { + DWORD typeReturned; + wchar_t regSubKey[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run\\"; -NGuid Overseer::getGuid() { - return guid; -} - -std::vector Overseer::getPlaybackEndpoints() { - return playbackDevices; -} + if(!onStartup) { + HKEY runKey; + if (RegOpenKeyExW( + scope, + regSubKey, + 0, + KEY_SET_VALUE, + &runKey + ) + == ERROR_SUCCESS) { + RegDeleteValueW(runKey, LAPP_NAME); + RegCloseKey(runKey); + } + } else { + LSTATUS result; + uint32_t cPathLen = 0; + wchar_t* cPath = getExeAbsPath(&cPathLen); + wchar_t* regPath = (wchar_t*)calloc(UNICODE_STRING_MAX_CHARS + 2, sizeof(wchar_t)); + //char* v = 0xFF'00'00'00'00'00'00'21; + regPath[0] = L'"'; + memcpy(regPath + 1, cPath, sizeof(wchar_t) * cPathLen); + memcpy(regPath + cPathLen + 1, L"\"", sizeof(wchar_t) * 2); -std::vector Overseer::getCaptureEndpoints() { - return captureDevices; -} - -void Overseer::updateEndpointInfo(std::wstring endpointId) { - log_wdebugcpp(L"new name Endpoint id: " + endpointId); - //todo: reintroduce capture devices - for(auto ep : playbackDevices) { - if (ep->getId() == endpointId) { - ep->updateName(); - osh->updateFrontEndpointName(ep); - break; - } + result = RegSetKeyValueW( + scope, + regSubKey, + LAPP_NAME, + REG_SZ, + (void*)regPath, + (cPathLen + 3) * sizeof(wchar_t)); + /* + * if (result != ERROR_SUCCESS) { + * wchar_t* error; + * FormatMessageW( + * FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + * nullptr, + * (DWORD)result, + * LANG_USER_DEFAULT, + * error, + * 1, + * nullptr); + * LocalFree(error); + * } + */ + free(cPath); } + return; } -Overseer::~Overseer(){ - log_debugcpp("cum"); - deviceEnumerator->Release(); - for(unsigned long long i = 0; i < playbackDevices.size(); i++){ - delete(playbackDevices.at(i)); +void Environment::setStartupConfig(bool onStartup) { + uint32_t cPathLen = 0; + wchar_t* cPath = getExeAbsPath(&cPathLen); + wchar_t startupParam[] = L"--change-startup"; + uint32_t startupParamLen = (sizeof(startupParam) / sizeof(wchar_t)) - 1; + wchar_t* completeParam = (wchar_t*)calloc(startupParamLen + 3, sizeof(wchar_t)); + memcpy(completeParam, startupParam, sizeof(wchar_t) * startupParamLen); + if (onStartup) + memcpy(completeParam + startupParamLen, L" 1", sizeof(wchar_t) * 3); + else + memcpy(completeParam + startupParamLen, L" 0", sizeof(wchar_t) * 3); + + if(scope == HKEY_LOCAL_MACHINE) { + ShellExecuteW( + NULL, + L"runas", + cPath, + completeParam, + NULL, // default dir + SW_SHOWNORMAL + ); + } else { + Environment::updateStartupConfig(onStartup); } + free(cPath); + free(completeParam); + return; +} + +bool Environment::isLightMode() { + return lightMode; +} + +bool Environment::isToRunAtStartup() { + return startup; +} + +uint32_t Environment::getAccentColor() { + return accentColor; } //int Overseer::getCaptureEndpoints(std::vector *captureEndpoints); diff --git a/src/back/backlasses.h b/src/back/backlasses.h index 4e67a09..7c7c412 100644 --- a/src/back/backlasses.h +++ b/src/back/backlasses.h @@ -4,10 +4,13 @@ #include "backsessionclasses.h" #include "global.h" #include "contclasses.h" +//#include "environment.h" class EndpointVolumeCallback; class Session; -std::string getPath(SettingsTargetDirectory target, bool create); + +wchar_t* getExeAbsPath(uint32_t *exeAbsPathLength); +std::string getSettingsPath(SettingsTargetDirectory target, bool create); // Convert a wide UTF16LE string to an UTF8 string static inline std::string utf16ToUtf8(const wchar_t* wstr) { @@ -146,12 +149,6 @@ class Overseer { public: Overseer(); NGuid getGuid(); - void populateSystemValues(); - void openControlPanel(); - ProcessedNativeEvent processTopLevelWindowMessage(void* msg); - ProcessedNativeEvent updateColors(); - bool isLightMode(); - uint32_t getAccentColor(); std::vector getPlaybackEndpoints(); std::vector getCaptureEndpoints(); @@ -171,11 +168,11 @@ class Overseer { ~Overseer(); private: + std::wstring exeAbsPath; + void initCOMLibrary(); NGuid guid; - bool lightMode; - uint32_t accentColor; IMMDeviceEnumerator *deviceEnumerator; EndpointSituationCallback epsc; @@ -202,3 +199,22 @@ class EndpointNewSessionCallback : public IAudioSessionNotification { ULONG ref = 1; EndpointHandler *eph; }; + +namespace Environment { + void populateSystemValues(); + void openControlPanel(); + ProcessedNativeEvent processTopLevelWindowMessage(void* msg); + ProcessedNativeEvent updateColors(); + bool checkStartup(HKEY rootKeyFlags); + void updateStartupConfig(bool onStartup); + void setStartupConfig(bool onStartup); + bool isLightMode(); + bool isToRunAtStartup(); + uint32_t getAccentColor(); + + static std::wstring exeAbsPath; + static bool lightMode; + static bool startup = false; + static HKEY scope; + static uint32_t accentColor; +}; diff --git a/src/cont/contclasses.cpp b/src/cont/contclasses.cpp index 067a32f..368f466 100644 --- a/src/cont/contclasses.cpp +++ b/src/cont/contclasses.cpp @@ -3,7 +3,7 @@ void setConfigDirToDefaults() { #define tryFileDir(dir, create) do { \ - OverseerHandler::settingsPath = getPath(dir, create); \ + OverseerHandler::settingsPath = getSettingsPath(dir, create); \ set = ini::UserSettings::createSettings(OverseerHandler::settingsPath.c_str()); \ if(set) { \ return; \ @@ -247,24 +247,36 @@ std::string OverseerHandler::getSettingsPath(){ return OverseerHandler::settingsPath; } +void OverseerHandler::updateStartupConfig(bool onStartup) { + Environment::updateStartupConfig(onStartup); +} + +void OverseerHandler::setStartupConfig(bool onStartup) { + Environment::setStartupConfig(onStartup); +} + void OverseerHandler::populateSystemValues() { - this->os->populateSystemValues(); + Environment::populateSystemValues(); } void OverseerHandler::openControlPanel() { - this->os->openControlPanel(); + Environment::openControlPanel(); } ProcessedNativeEvent OverseerHandler::processTopLevelWindowMessage(void* msg) { - return this->os->processTopLevelWindowMessage(msg); + return Environment::processTopLevelWindowMessage(msg); } bool OverseerHandler::isLightMode() { - return this->os->isLightMode(); + return Environment::isLightMode(); +} + +bool OverseerHandler::isToRunAtStartup() { + return Environment::isToRunAtStartup(); } uint32_t OverseerHandler::getAccentColor() { - return this->os->getAccentColor(); + return Environment::getAccentColor(); } std::vector OverseerHandler::getPlaybackEndpoints() { diff --git a/src/cont/contclasses.h b/src/cont/contclasses.h index 2a4a9f0..ac4ecdc 100644 --- a/src/cont/contclasses.h +++ b/src/cont/contclasses.h @@ -105,10 +105,13 @@ public: static void setSettingsPath(std::string path); static std::string getSettingsPath(); static inline std::string settingsPath; + void updateStartupConfig(bool onStartup); + void setStartupConfig(bool onStartup); void populateSystemValues(); void openControlPanel(); ProcessedNativeEvent processTopLevelWindowMessage(void* msg); bool isLightMode(); + bool isToRunAtStartup(); uint32_t getAccentColor(); //void setChangeFrontDefaultsFunction(std::function changeFrontDefaults); diff --git a/src/debug.h b/src/debug.h index 176825a..d4b9195 100644 --- a/src/debug.h +++ b/src/debug.h @@ -2,6 +2,8 @@ #if defined (QT_DEBUG) || defined (DEBUG) || defined (_DEBUG) +#define PIPE_NAME "Mixerq-dev" + #ifdef INIT_FILELOG std::wstring_convert, wchar_t> converter; FILE* fileLog; @@ -72,7 +74,8 @@ std::bitset varToBitset(T info) { #define print_as_binary(info) #define log_to_file(fmt, cnt...) #define initialize_file_log() false -#define close_file_log_buffer() +#define close_file_log_buffer() +#define PIPE_NAME "Mixerq" #endif /* Here as a quick reference, in case smthn similar is needed again */ diff --git a/src/global.h b/src/global.h index 7c02902..ba5678b 100644 --- a/src/global.h +++ b/src/global.h @@ -16,6 +16,9 @@ //#include "settings.h" //TODO: Use tr();? QTranslator +#define APP_NAME "MixerQ" +#define LAPP_NAME L"MixerQ" + #define STRING_MUTE "Mute" #define STRING_UNMUTE "Unmute" #define STRING_QUIT "Quit" @@ -38,7 +41,6 @@ #define LSTRING_UNNAMED_SESSION L"Unnamed session" - //INIT BACK enum SettingsTargetDirectory { diff --git a/src/qt/qtclasses.cpp b/src/qt/qtclasses.cpp index 15f3768..fa91703 100644 --- a/src/qt/qtclasses.cpp +++ b/src/qt/qtclasses.cpp @@ -37,7 +37,6 @@ CustomWidgetEvent::CustomWidgetEvent(QEvent::Type type, T payload) : QEvent(t this->payload = payload; } - /* * MeterSlider::MeterSlider(Qt::Orientation orientation, QWidget* parent) { * //style = new MixerStyle(); @@ -225,7 +224,7 @@ QRect MainWindow::setSizePosition(QScreen* screen, int width, int height) { QRect availableRes = screen->availableGeometry(); int arx1, arx2, ary1, ary2; availableRes.getCoords(&arx1, &ary1, &arx2, &ary2); - log_debugcpp("Available res: " + std::to_string(arx1) + " " + std::to_string(arx2)+" " + std::to_string(ary1) + " " + std::to_string(ary2);) + log_debugcpp("Available res: " + std::to_string(arx1) + " " + std::to_string(arx2)+" " + std::to_string(ary1) + " " + std::to_string(ary2)); if(height > (ary2 - ary1)) height = (ary2 - ary1); log_debugcpp("Height res: " + std::to_string(height)); @@ -959,11 +958,15 @@ HeaderWidget::HeaderWidget(QWidget *parent) : QWidget(parent) { } }); - text = "&" STRING_STARTUP; startup = new QCheckBox(text, this); - //connect(openCP, &QPushButton::clicked, [](){ osh->openControlPanel(); }); + if(osh->isToRunAtStartup()) { + startup->setChecked(true); + } + connect(startup, &QCheckBox::stateChanged, [this](){ + osh->setStartupConfig(startup->isChecked()); + }); widgetLayout->addWidget(openCP , 0, 0, 2, 2); widgetLayout->addWidget(channels, 0, 2, 1, 2); diff --git a/src/qtestmain.cpp b/src/qtestmain.cpp index 8b34385..b036c72 100644 --- a/src/qtestmain.cpp +++ b/src/qtestmain.cpp @@ -7,13 +7,16 @@ OverseerHandler *osh = nullptr; ini::UserSettings *set = nullptr; - -QApplication* createApplication(int &argc, char *argv[]) -{ + +bool startupRun = false; +bool onStartup = false; +char* userSettingsPath = nullptr; + +QApplication* createApplication(int &argc, char *argv[]) { return new QApplication(argc, argv); } -bool isSingleInstanceRunning(QString appName) { +bool isInstanceRunning(QString appName) { QLocalSocket socket; socket.connectToServer(appName); bool isOpen = socket.isOpen(); @@ -21,7 +24,7 @@ bool isSingleInstanceRunning(QString appName) { return isOpen; } -QLocalServer* startSingleInstanceServer(QString appName) { +QLocalServer* startInstanceServer(QString appName) { QLocalServer* server = new QLocalServer; server->setSocketOptions(QLocalServer::WorldAccessOption); server->listen(appName); @@ -32,12 +35,34 @@ 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; +void parseCmdArgs(int argc, char* argv[]) { + if(argc == 1) return; + //char* configPath = nullptr; + char* arg[] = { (char*)"--config-path=", (char*)"--change-startup" }; + + for (int i = 1; i < argc; i++) { + if(strstr(argv[i], arg[0])) { + userSettingsPath = argv[i] + strlen(arg[0]); + } + + if(strstr(argv[i], arg[1])) { + if (++i >= argc) return; + switch (argv[i][0]) { + case '0': + startupRun = true; + onStartup = false; + break; + case '1': + startupRun = true; + onStartup = true; + break; + default: + break; + } + return; + } + } + return; } /* set_terminate @@ -48,41 +73,49 @@ char* parseCmdArgs(int argc, char* argv[]) { */ int main (int argc, char* argv[]) { - /* - * QStringList styles = QStyleFactory::keys(); - * for(QString a : styles) { - * log_debugcpp(a.toStdString()); - * } + * Debug: logging report file */ - char* userSettingsPath = parseCmdArgs(argc, argv); - if (userSettingsPath) - set = ini::UserSettings::createSettings(userSettingsPath, true); - - if (set) - OverseerHandler::settingsPath = std::string(userSettingsPath); - else setConfigDirToDefaults(); - initialize_file_log(); atexit(closeDebugFileLog); - //Check if running - //https://stackoverflow.com/questions/48060989/qt-show-application-if-currently-running - //std::set_terminate(closeDebugFileLog2); - if (!isSingleInstanceRunning("Mixer")) - startSingleInstanceServer("Mixer"); - else exit(0); - - QApplication::setStyle(new MixerStyle(QStyleFactory::create("Fusion"))); //QApplication::setFont(font); //QPalette palette = QGuiApplication::palette(); - //todo: ez full apply os accent colorw + //palette.setColor(QPalette::Active, QPalette::Highlight, QColor(255, 192, 203, 200)); //QColor(30,30,30,100)); //QGuiApplication::setPalette(palette); osh = new OverseerHandler(); osh->populateSystemValues(); + + /* + * Arg parsing: (admin?) startup change run + */ + parseCmdArgs(argc, argv); + if (startupRun) { + if (!isInstanceRunning(PIPE_NAME)) exit(-1); + //if (startupChangeInfo->permissionChangeScope == NONE) exit(-1); + osh->updateStartupConfig(onStartup); + exit(0); + } + + //Check if running + //https://stackoverflow.com/questions/48060989/qt-show-application-if-currently-running + if (!isInstanceRunning(PIPE_NAME)) + startInstanceServer(PIPE_NAME); + else exit(0); + + /* + * Config file init + */ + if (userSettingsPath) + set = ini::UserSettings::createSettings(userSettingsPath, true); + + if (set) + OverseerHandler::settingsPath = std::string(userSettingsPath); + else setConfigDirToDefaults(); + StylingHelper::setBackgroundColor(osh->isLightMode()); //qRegisterMetaType();