/** * Sigstoped * Copyright (C) 2020 Carl Klemm * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 3 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #define __USE_POSIX #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xinstance.h" #include "process.h" #include "split.h" #include "debug.h" #include "argpopt.h" Window intraCommesWindow; XInstance xinstance; volatile bool stop = false; volatile bool configStale = false; constexpr char configPrefix[] = "/.config/sigstoped/"; void sigTerm(int dummy) { stop = true; XClientMessageEvent dummyEvent; memset(&dummyEvent, 0, sizeof(XClientMessageEvent)); dummyEvent.type = ClientMessage; dummyEvent.window = intraCommesWindow; dummyEvent.format = 32; XSendEvent(xinstance.display, intraCommesWindow, 0, 0, (XEvent*)&dummyEvent); xinstance.flush(); } void sigUser1(int dummy) { configStale = true; } std::string getConfdir() { const char* homeDir = getenv("HOME"); if(homeDir == nullptr) { std::cerr<<"HOME enviroment variable must be set.\n"; return std::string(); } const std::string configDir(std::string(homeDir)+configPrefix); if (std::filesystem::exists(configDir)) { return std::string(homeDir)+configPrefix; } else if(!std::filesystem::create_directory(configDir, homeDir)) { std::cout<<"Can't create "< getApplicationlist(const std::string& fileName) { std::fstream blacklistFile; blacklistFile.open(fileName, std::fstream::in); std::string blacklistString; if(!blacklistFile.is_open()) { std::cout<(); } } else { blacklistString.assign((std::istreambuf_iterator(blacklistFile)), std::istreambuf_iterator()); } return split(blacklistString); } bool createPidFile(const std::string& fileName) { if(std::filesystem::exists(fileName)) { std::cerr< 1) return false; else { std::cerr<<"Only one " < applicationNames = getApplicationlist(confDir+"blacklist"); if(applicationNames.size() == 0) std::cout<<"WARNIG: no application names configured.\n"; if( !std::filesystem::exists("/proc") ) { std::cerr<<"proc must be mounted!\n"; return 1; } char* xDisplayName = std::getenv( "DISPLAY" ); if(xDisplayName == nullptr) { std::cerr<<"DISPLAY enviroment variable must be set.\n"; return 1; } std::list stoppedProcs; if(!xinstance.open(xDisplayName)) exit(1); intraCommesWindow = XCreateSimpleWindow(xinstance.display, RootWindow(xinstance.display, xinstance.screen), 10, 10, 10, 10, 0, 0, 0); XSelectInput(xinstance.display, intraCommesWindow, StructureNotifyMask); XSelectInput(xinstance.display, RootWindow(xinstance.display, xinstance.screen), PropertyChangeMask | StructureNotifyMask); XEvent event; Process prevProcess; Window prevWindow = 0; signal(SIGINT, sigTerm); signal(SIGTERM, sigTerm); signal(SIGHUP, sigTerm); signal(SIGUSR1, sigUser1); while(!stop) { XNextEvent(xinstance.display, &event); if (event.type == DestroyNotify) break; if (event.type == PropertyNotify && event.xproperty.atom == xinstance.atoms.netActiveWindow) { Window wid = xinstance.getActiveWindow(); if(wid != 0 && wid != prevWindow) { pid_t windowPid = xinstance.getPid(wid); Process process(windowPid); std::cout<<"Active window: "< 0 && process.getName() != "") { process.resume(true); stoppedProcs.remove(process); std::cout<<"Resumeing wid: "+std::to_string(wid)+" pid: "+std::to_string(process.getPid())+" name: "+process.getName()<<'\n'; } else if(prevProcess.getName() == applicationNames[i] && prevWindow != 0 && prevProcess.getName() != "" && prevProcess.getPid() > 0) { sleep(5); //give the process some time to close its other windows bool hasTopLevelWindow = false; std::vector tlWindows = xinstance.getTopLevelWindows(); for(auto& window : tlWindows) { if(xinstance.getPid(window) == prevProcess.getPid()) hasTopLevelWindow = true; } if(hasTopLevelWindow) { prevProcess.stop(true); std::cout<<"Stoping wid: "+std::to_string(prevWindow)+" pid: "+std::to_string(prevProcess.getPid())+" name: "+prevProcess.getName()<<'\n'; stoppedProcs.push_back(prevProcess); } else std::cout<<"not Stoping wid: "+std::to_string(prevWindow)+" pid: "+std::to_string(prevProcess.getPid())+" name: "+prevProcess.getName()<<'\n'; } } } prevProcess = process; prevWindow = wid; } } } for(auto& process : stoppedProcs) process.resume(true); std::filesystem::remove(confDir+"pidfile"); return 0; }