/** * 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" #include "CppTimer.h" Window intraCommesWindow; volatile bool configStale = false; XInstance xinstance; constexpr char configPrefix[] = "/.config/sigstoped/"; constexpr char STOP_EVENT = 65; constexpr char PROC_STOP_EVENT = 1; void sigTerm(int dummy) { XClientMessageEvent event; memset(&event, 0, sizeof(XClientMessageEvent)); event.type = ClientMessage; event.window = intraCommesWindow; event.format = 8; event.data.b[0] = STOP_EVENT; XLockDisplay(xinstance.display); XSendEvent(xinstance.display, intraCommesWindow, 0, 0, (XEvent*)&event); XUnlockDisplay(xinstance.display); 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 " < tlWindows = xinstance->getTopLevelWindows(); for(auto& window : tlWindows) { if(xinstance->getPid(window) == process.getPid()) hasTopLevelWindow = true; } if(hasTopLevelWindow) { process.stop(true); std::cout<<"Stoping pid: "+std::to_string(process.getPid())+" name: "+process.getName()<<'\n'; return true; } else { std::cout<<"not Stoping pid: "+std::to_string(process.getPid())+" name: "+process.getName()<<'\n'; return false; } } int main(int argc, char* argv[]) { char* xDisplayName = std::getenv( "DISPLAY" ); if(xDisplayName == nullptr) { std::cerr<<"DISPLAY enviroment variable must be set.\n"; return 1; } if(!xinstance.open(xDisplayName)) exit(1); Config config; argp_parse(&argp, argc, argv, 0, 0, &config); if(config.ignoreClientMachine) { std::cout<<"WARNING: Ignoring WM_CLIENT_MACHINE is dangerous and may cause sigstoped to stop random pids if remote windows are present"< 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; } std::list stoppedProcs; 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; Process qeuedToStop; Window prevWindow = 0; signal(SIGINT, sigTerm); signal(SIGTERM, sigTerm); signal(SIGHUP, sigTerm); signal(SIGUSR1, sigUser1); CppTimer timer; while(true) { XNextEvent(xinstance.display, &event); if (event.type == DestroyNotify) break; else 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() != "") { if(process == qeuedToStop) { std::cout<<"Canceling stop of wid: "+std::to_string(wid)+" pid: "+std::to_string(process.getPid())+" name: "+process.getName()<<'\n'; timer.stop(); qeuedToStop = Process(); } 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) { timer.block(); std::cout<<"Will stop pid: "<window == intraCommesWindow) { XClientMessageEvent* clientEvent = (XClientMessageEvent*)&event; if (clientEvent->data.b[0] == STOP_EVENT) break; if (clientEvent->data.b[0] == PROC_STOP_EVENT) { stopProcess(qeuedToStop, &xinstance); qeuedToStop = Process(); } } } for(auto& process : stoppedProcs) process.resume(true); std::filesystem::remove(confDir+"pidfile"); return 0; }