From 915532bf8fbda9ba2a36e04fcd6acc67c6c68fa5 Mon Sep 17 00:00:00 2001 From: BossCode45 Date: Tue, 1 Oct 2024 14:54:37 +1300 Subject: Restructure --- IPC.cpp | 86 ---- IPC.h | 26 - YATmsg/main.cpp | 0 commands.cpp | 335 ------------- commands.h | 89 ---- compile_commands.json | 156 +++--- config.cpp | 132 ------ config.h | 53 --- error.h | 26 - ewmh.cpp | 101 ---- ewmh.h | 25 - keybinds.cpp | 282 ----------- keybinds.h | 59 --- main.cpp | 1159 --------------------------------------------- makefile | 10 +- old.compile_commands.json | 128 +++++ src/IPC.cpp | 86 ++++ src/IPC.h | 26 + src/commands.cpp | 335 +++++++++++++ src/commands.h | 89 ++++ src/config.cpp | 132 ++++++ src/config.h | 53 +++ src/error.h | 26 + src/ewmh.cpp | 101 ++++ src/ewmh.h | 25 + src/keybinds.cpp | 282 +++++++++++ src/keybinds.h | 59 +++ src/main.cpp | 1159 +++++++++++++++++++++++++++++++++++++++++++++ src/structs.h | 48 ++ src/util.cpp | 32 ++ src/util.h | 19 + structs.h | 48 -- test | 2 +- util.cpp | 32 -- util.h | 19 - 35 files changed, 2684 insertions(+), 2556 deletions(-) delete mode 100644 IPC.cpp delete mode 100644 IPC.h create mode 100644 YATmsg/main.cpp delete mode 100644 commands.cpp delete mode 100644 commands.h delete mode 100644 config.cpp delete mode 100644 config.h delete mode 100644 error.h delete mode 100644 ewmh.cpp delete mode 100644 ewmh.h delete mode 100644 keybinds.cpp delete mode 100644 keybinds.h delete mode 100644 main.cpp create mode 100644 old.compile_commands.json create mode 100644 src/IPC.cpp create mode 100644 src/IPC.h create mode 100644 src/commands.cpp create mode 100644 src/commands.h create mode 100644 src/config.cpp create mode 100644 src/config.h create mode 100644 src/error.h create mode 100644 src/ewmh.cpp create mode 100644 src/ewmh.h create mode 100644 src/keybinds.cpp create mode 100644 src/keybinds.h create mode 100644 src/main.cpp create mode 100644 src/structs.h create mode 100644 src/util.cpp create mode 100644 src/util.h delete mode 100644 structs.h delete mode 100644 util.cpp delete mode 100644 util.h diff --git a/IPC.cpp b/IPC.cpp deleted file mode 100644 index 0aed97e..0000000 --- a/IPC.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "IPC.h" -#include "ewmh.h" - -#include -#include -#include -#include -#include - -using std::cout, std::endl; - -static const char* path = "/tmp/YATwm.sock"; - -IPCModule::IPCModule(CommandsModule& commandsModule, Config& cfg, Globals& globals) - :commandsModule(commandsModule), - cfg(cfg), - globals(globals) -{ - sockfd = socket(AF_UNIX, SOCK_STREAM, 0); - address.sun_family = AF_UNIX; - strcpy(address.sun_path, path); - unlink(address.sun_path); - len = strlen(address.sun_path) + sizeof(address.sun_family); - - if(bind(sockfd, (sockaddr*)&address, len) == -1) - { - cout << "ERROR " << errno << endl; - } - cout << "SOCKETED" << endl; -} - -void IPCModule::init() -{ - setIPCPath((unsigned char*)path, strlen(path)); -} - -void IPCModule::doListen() -{ - if(listen(sockfd, 1) != 0) - { - cout << "ERROR 2" << endl; - return; - } - if(first) - { - first = false; - return; - } - cout << "DOLISTEN" << endl; - unsigned int socklen = 0; - sockaddr_un remote; - int newsock = accept(sockfd, (sockaddr*)&remote, &socklen); - cout << "LISTENING" << endl; - char buffer[256]; - memset(buffer, 0, 256); - read(newsock, buffer, 256); - std::string command(buffer); - while(command[command.size() - 1] == 0 || command[command.size() - 1] == '\n') - command = command.substr(0, command.size() - 1); - //cout << '"' << command << '"' << endl; - try - { - commandsModule.runCommand(command); - } - catch(Err e) - { - cout << e.code << " " << e.message << endl; - } - char* message = "RAN COMMAND"; - send(newsock, message, strlen(message), 0); - cout << "RAN COMMAND" << endl; - shutdown(newsock, SHUT_RDWR); - close(newsock); -} - -void IPCModule::quitIPC() -{ - close(sockfd); -} - -int IPCModule::getFD() -{ - if(sockfd > 0) - return sockfd; - return -1; -} diff --git a/IPC.h b/IPC.h deleted file mode 100644 index 89e67e5..0000000 --- a/IPC.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include - -#include "commands.h" -#include "config.h" -#include "util.h" - -class IPCModule -{ -public: - IPCModule(CommandsModule& commandsModule, Config& cfg, Globals& globals); - void init(); - void doListen(); - void quitIPC(); - int getFD(); -private: - CommandsModule& commandsModule; - Config& cfg; - Globals& globals; - int sockfd; - int len; - bool first = true; - sockaddr_un address; -}; diff --git a/YATmsg/main.cpp b/YATmsg/main.cpp new file mode 100644 index 0000000..e69de29 diff --git a/commands.cpp b/commands.cpp deleted file mode 100644 index 57cfd0b..0000000 --- a/commands.cpp +++ /dev/null @@ -1,335 +0,0 @@ -#include "commands.h" -#include "error.h" -#include "util.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using std::cout, std::endl, std::string, std::vector; - -const void CommandsModule::echo(const CommandArg* argv) -{ - cout << argv[0].str << endl; -} - -CommandsModule::CommandsModule() -{ - addCommand("echo", &CommandsModule::echo, 1, {STR_REST}, this); -} -CommandsModule::~CommandsModule() -{ - for(Command c : commandList) - { - if(c.argc > 0) - delete[] c.argTypes; - } -} - -void CommandsModule::addCommand(Command c) -{ - if(lookupCommand(c.name) != nullptr) - { - cout << "Duplicate command: " << c.name << endl; - } - commandList.push_back(c); -} -void CommandsModule::addCommand(std::string name, const void (*func)(const CommandArg *), const int argc, CommandArgType *argTypes) -{ - Command c = {name, nullptr, func, argc, argTypes, nullptr}; - addCommand(c); -} -void CommandsModule::addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, std::vector argTypes) -{ - CommandArgType* argTypesArr = new CommandArgType[argc]; - for(int i = 0; i < argc; i++) - { - argTypesArr[i] = argTypes[i]; - } - addCommand(name, func, argc, argTypesArr); -} - -struct NameMatches -{ - NameMatches(string s): s_{s} {} - bool operator()(Command c) { return (c.name == s_); } - string s_; -}; - -Command* CommandsModule::lookupCommand(string name) -{ - auto elem = std::find_if(commandList.begin(), commandList.end(), NameMatches(name)); - if (elem != commandList.end()) - { - int i = elem - commandList.begin(); - return &(commandList[i]); - } - else - { - return nullptr; - } -} - -vector CommandsModule::splitCommand(string command) -{ - vector v; - string arg = ""; - bool inQuotes = false; - bool escapeNext = true; - char quoteType; - for(int i = 0; i < command.size(); i++) - { - if(escapeNext) - { - arg += command[i]; - escapeNext = false; - } - else if(command[i] == '\\') - { - escapeNext = true; - } - else if(inQuotes) - { - if(command[i] == quoteType) - { - if(arg != "") - { - v.push_back(arg); - arg = ""; - } - inQuotes = false; - } - else - { - arg += command[i]; - } - } - else - { - if(command[i] == ' ') - { - if(arg != "") - { - v.push_back(arg); - arg = ""; - } - } - else if(command[i] == '"' || command[i] == '\'') - { - inQuotes = true; - quoteType = command[i]; - } - else - { - arg += command[i]; - } - } - } - if(arg != "") - v.push_back(arg); - return v; -} - -CommandArg* CommandsModule::getCommandArgs(vector& split, const CommandArgType* argTypes, const int argc) -{ - CommandArg* args = new CommandArg[argc]; - for(int i = 1; i < argc + 1; i++) - { - switch(argTypes[i-1]) - { - case STR: args[i-1].str = (char*)split[i].c_str(); break; - case NUM: - { - try - { - args[i-1].num = std::stoi(split[i]); - break; - } - catch(std::invalid_argument e) - { - delete[] args; - throw Err(CMD_ERR_WRONG_ARGS, split[i] + " is not a number!"); - } - } - case MOVDIR: - { - if(lowercase(split[i]) == "up") - args[i-1].dir = UP; - else if(lowercase(split[i]) == "down") - args[i-1].dir = DOWN; - else if(lowercase(split[i]) == "left") - args[i-1].dir = LEFT; - else if(lowercase(split[i]) == "right") - args[i-1].dir = RIGHT; - else - { - delete[] args; - throw Err(CMD_ERR_WRONG_ARGS, split[i] + " is not a direction!"); - } - break; - } - case STR_REST: - { - string rest = ""; - for(int j = i; j < split.size(); j++) - { - rest += split[j]; - if(j != split.size() - 1) - rest += " "; - } - args[i-1].str = new char[rest.size()]; - strcpy(args[i-1].str, rest.c_str()); - return args; - } - case NUM_ARR_REST: - { - int* rest = new int[split.size() - i]; - for(int j = 0; j < split.size() - i; j++) - { - try - { - rest[j] = std::stoi(split[j + i]); - } - catch(std::invalid_argument e) - { - delete[] rest; - delete[] args; - throw Err(CMD_ERR_WRONG_ARGS, split[i] + " is not a number!"); - } - } - args[i-1].numArr = {rest, (int) split.size() - i}; - return args; - } - default: cout << "UH OH SOMETHING IS VERY WRONG" << endl; - } - } - return args; -} - -void CommandsModule::runCommand(string command) -{ - vector split = splitCommand(command); - vector::const_iterator start = split.begin(); - int count = 0; - for(string s : split) - { - if(s == ";") - { - vector::const_iterator end = start + count; - vector partialCmd(start, end); - runCommand(partialCmd); - count = 0; - start = end + 1; - } - else - { - count++; - } - } - if(start != split.end()) - { - vector partialCmd(start, (vector::const_iterator)split.end()); - runCommand(partialCmd); - } -} -void CommandsModule::runCommand(vector split) -{ - Command* cmd = lookupCommand(split[0]); - if(cmd == nullptr) - throw Err(CMD_ERR_NOT_FOUND, split[0] + " is not a valid command name"); - if(cmd->argc > split.size() - 1) - throw Err(CMD_ERR_WRONG_ARGS, "wrong number of arguments"); - CommandArg* args; - try - { - args = getCommandArgs(split, cmd->argTypes, cmd->argc); - } - catch(Err e) - { - throw e; - } - try - { - if(cmd->module == nullptr) - cmd->staticFunc(args); - else - cmd->func(*cmd->module, args); - } - catch (Err e) - { - for(int i = 0; i < cmd->argc; i++) - { - if(cmd->argTypes[i] == STR_REST) - delete[] args[i].str; - } - delete[] args; - throw e; - } - for(int i = 0; i < cmd->argc; i++) - { - if(cmd->argTypes[i] == STR_REST) - delete[] args[i].str; - } - delete[] args; -} - -vector CommandsModule::checkCommand(string command) -{ - vector errs; - vector split = splitCommand(command); - vector::const_iterator start = split.begin(); - int count = 0; - for(string s : split) - { - if(s == ";") - { - vector::const_iterator end = start + count; - vector partialCmd(start, end); - errs.push_back(checkCommand(partialCmd)); - count = 0; - start = end + 1; - } - else - { - count++; - } - } - if(start != split.end()) - { - vector partialCmd(start, (vector::const_iterator)split.end()); - errs.push_back(checkCommand(partialCmd)); - } - return errs; -} - -Err CommandsModule::checkCommand(vector split) -{ - Command* cmd = lookupCommand(split[0]); - if(cmd == nullptr) - return Err(CMD_ERR_NOT_FOUND, split[0] + " is not a valid command name"); - if(cmd->argc > split.size()) - return Err(CMD_ERR_WRONG_ARGS, "wrong number of arguments"); - CommandArg* args; - try - { - args = getCommandArgs(split, cmd->argTypes, cmd->argc); - } - catch(Err e) - { - return e; - } - for(int i = 0; i < cmd->argc; i++) - { - if(cmd->argTypes[i] == STR_REST || cmd->argTypes[i] == NUM_ARR_REST) - delete[] args[i].str; - } - delete[] args; - return Err(NOERR, ""); -} diff --git a/commands.h b/commands.h deleted file mode 100644 index af4a4a0..0000000 --- a/commands.h +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#include "error.h" - -#include -#include -#include -#include - -enum MoveDir - { - UP, - RIGHT, - DOWN, - LEFT - }; -enum CommandArgType - { - STR, - NUM, - MOVDIR, - STR_REST, - NUM_ARR_REST - }; - -struct NumArr -{ - int* arr; - int size; -}; -typedef union -{ - char* str; - int num; - NumArr numArr; - MoveDir dir; -} CommandArg; - -struct Command -{ - const std::string name; - const std::function func; - const std::function staticFunc; - const int argc; - CommandArgType* argTypes; - std::any* module; -}; -class CommandsModule -{ -private: - std::vector commandList; - std::vector splitCommand(std::string command); - CommandArg* getCommandArgs(std::vector& args, const CommandArgType* argTypes, const int argc); - const void echo(const CommandArg* argv); -public: - CommandsModule(); - ~CommandsModule(); - template - void addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, CommandArgType* argTypes, T* module); - void addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, CommandArgType* argTypes); - template - void addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, std::vector argTypes, T* module); - void addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, std::vector argTypes); - void addCommand(Command c); - Command* lookupCommand(std::string name); - void runCommand(std::string command); - void runCommand(std::vector split); - std::vector checkCommand(std::string command); - Err checkCommand(std::vector split); -}; - -// YES I KNOW THIS IS BAD -// but it needs to be done this way -template -void CommandsModule::addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, CommandArgType* argTypes, T* module) -{ - Command c = {name, (const void*(std::any::*)(const CommandArg* argv)) func, nullptr, argc, argTypes, (std::any*)module}; - addCommand(c); -} -template -void CommandsModule::addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, std::vector argTypes, T* module) -{ - CommandArgType* argTypesArr = new CommandArgType[argc]; - for(int i = 0; i < argc; i++) - { - argTypesArr[i] = argTypes[i]; - } - addCommand(name, func, argc, argTypesArr, module); -} diff --git a/compile_commands.json b/compile_commands.json index 3997f42..aa66e68 100644 --- a/compile_commands.json +++ b/compile_commands.json @@ -1,128 +1,128 @@ [ { "arguments": [ - "/usr/bin/g++", + "/nix/store/9bv7dcvmfcjnmg5mnqwqlq2wxfn8d7yi-gcc-wrapper-13.2.0/bin/g++", "-std=c++17", - "-I/usr/include/gdk-pixbuf-2.0", - "-I/usr/include/glib-2.0", - "-I/usr/lib64/glib-2.0/include", - "-I/usr/include/sysprof-4", - "-I/usr/include/libpng16", - "-I/usr/include/libmount", - "-I/usr/include/blkid", - "-pthread", + "-I/nix/store/drrf5w7pcc5q9h4si9i8vm2hclg0zijg-libnotify-0.8.3-dev/include", + "-I/nix/store/a45ri2jgzpv6q36va2y6wq471y88hpnl-gdk-pixbuf-2.42.10-dev/include/gdk-pixbuf-2.0", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include/glib-2.0", + "-I/nix/store/k1qjs35nw1lbssg1l1xpmh0082hy7wl4-glib-2.78.4/lib/glib-2.0/include", "-c", "-o", - "ewmh.o", - "ewmh.cpp" + "build/config.o", + "src/config.cpp" ], "directory": "/home/boss/Documents/Coding/WM/YATwm", - "file": "/home/boss/Documents/Coding/WM/YATwm/ewmh.cpp", - "output": "/home/boss/Documents/Coding/WM/YATwm/ewmh.o" + "file": "/home/boss/Documents/Coding/WM/YATwm/src/config.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/build/config.o" }, { "arguments": [ - "/usr/bin/g++", + "/nix/store/9bv7dcvmfcjnmg5mnqwqlq2wxfn8d7yi-gcc-wrapper-13.2.0/bin/g++", "-std=c++17", - "-I/usr/include/gdk-pixbuf-2.0", - "-I/usr/include/glib-2.0", - "-I/usr/lib64/glib-2.0/include", - "-I/usr/include/sysprof-4", - "-I/usr/include/libpng16", - "-I/usr/include/libmount", - "-I/usr/include/blkid", - "-pthread", + "-I/nix/store/drrf5w7pcc5q9h4si9i8vm2hclg0zijg-libnotify-0.8.3-dev/include", + "-I/nix/store/a45ri2jgzpv6q36va2y6wq471y88hpnl-gdk-pixbuf-2.42.10-dev/include/gdk-pixbuf-2.0", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include/glib-2.0", + "-I/nix/store/k1qjs35nw1lbssg1l1xpmh0082hy7wl4-glib-2.78.4/lib/glib-2.0/include", "-c", "-o", - "main.o", - "main.cpp" + "build/ewmh.o", + "src/ewmh.cpp" ], "directory": "/home/boss/Documents/Coding/WM/YATwm", - "file": "/home/boss/Documents/Coding/WM/YATwm/main.cpp", - "output": "/home/boss/Documents/Coding/WM/YATwm/main.o" + "file": "/home/boss/Documents/Coding/WM/YATwm/src/ewmh.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/build/ewmh.o" }, { "arguments": [ - "/usr/bin/g++", + "/nix/store/9bv7dcvmfcjnmg5mnqwqlq2wxfn8d7yi-gcc-wrapper-13.2.0/bin/g++", "-std=c++17", - "-I/usr/include/gdk-pixbuf-2.0", - "-I/usr/include/glib-2.0", - "-I/usr/lib64/glib-2.0/include", - "-I/usr/include/sysprof-4", - "-I/usr/include/libpng16", - "-I/usr/include/libmount", - "-I/usr/include/blkid", - "-pthread", + "-I/nix/store/drrf5w7pcc5q9h4si9i8vm2hclg0zijg-libnotify-0.8.3-dev/include", + "-I/nix/store/a45ri2jgzpv6q36va2y6wq471y88hpnl-gdk-pixbuf-2.42.10-dev/include/gdk-pixbuf-2.0", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include/glib-2.0", + "-I/nix/store/k1qjs35nw1lbssg1l1xpmh0082hy7wl4-glib-2.78.4/lib/glib-2.0/include", "-c", "-o", - "util.o", - "util.cpp" + "build/main.o", + "src/main.cpp" ], "directory": "/home/boss/Documents/Coding/WM/YATwm", - "file": "/home/boss/Documents/Coding/WM/YATwm/util.cpp", - "output": "/home/boss/Documents/Coding/WM/YATwm/util.o" + "file": "/home/boss/Documents/Coding/WM/YATwm/src/main.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/build/main.o" }, { "arguments": [ - "/usr/bin/g++", + "/nix/store/9bv7dcvmfcjnmg5mnqwqlq2wxfn8d7yi-gcc-wrapper-13.2.0/bin/g++", "-std=c++17", - "-I/usr/include/gdk-pixbuf-2.0", - "-I/usr/include/glib-2.0", - "-I/usr/lib64/glib-2.0/include", - "-I/usr/include/sysprof-4", - "-I/usr/include/libpng16", - "-I/usr/include/libmount", - "-I/usr/include/blkid", - "-pthread", + "-I/nix/store/drrf5w7pcc5q9h4si9i8vm2hclg0zijg-libnotify-0.8.3-dev/include", + "-I/nix/store/a45ri2jgzpv6q36va2y6wq471y88hpnl-gdk-pixbuf-2.42.10-dev/include/gdk-pixbuf-2.0", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include/glib-2.0", + "-I/nix/store/k1qjs35nw1lbssg1l1xpmh0082hy7wl4-glib-2.78.4/lib/glib-2.0/include", "-c", "-o", - "config.o", - "config.cpp" + "build/IPC.o", + "src/IPC.cpp" ], "directory": "/home/boss/Documents/Coding/WM/YATwm", - "file": "/home/boss/Documents/Coding/WM/YATwm/config.cpp", - "output": "/home/boss/Documents/Coding/WM/YATwm/config.o" + "file": "/home/boss/Documents/Coding/WM/YATwm/src/IPC.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/build/IPC.o" }, { "arguments": [ - "/usr/bin/g++", + "/nix/store/9bv7dcvmfcjnmg5mnqwqlq2wxfn8d7yi-gcc-wrapper-13.2.0/bin/g++", "-std=c++17", - "-I/usr/include/gdk-pixbuf-2.0", - "-I/usr/include/glib-2.0", - "-I/usr/lib64/glib-2.0/include", - "-I/usr/include/sysprof-4", - "-I/usr/include/libpng16", - "-I/usr/include/libmount", - "-I/usr/include/blkid", - "-pthread", + "-I/nix/store/drrf5w7pcc5q9h4si9i8vm2hclg0zijg-libnotify-0.8.3-dev/include", + "-I/nix/store/a45ri2jgzpv6q36va2y6wq471y88hpnl-gdk-pixbuf-2.42.10-dev/include/gdk-pixbuf-2.0", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include/glib-2.0", + "-I/nix/store/k1qjs35nw1lbssg1l1xpmh0082hy7wl4-glib-2.78.4/lib/glib-2.0/include", "-c", "-o", - "keybinds.o", - "keybinds.cpp" + "build/util.o", + "src/util.cpp" ], "directory": "/home/boss/Documents/Coding/WM/YATwm", - "file": "/home/boss/Documents/Coding/WM/YATwm/keybinds.cpp", - "output": "/home/boss/Documents/Coding/WM/YATwm/keybinds.o" + "file": "/home/boss/Documents/Coding/WM/YATwm/src/util.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/build/util.o" }, { "arguments": [ - "/usr/bin/g++", + "/nix/store/9bv7dcvmfcjnmg5mnqwqlq2wxfn8d7yi-gcc-wrapper-13.2.0/bin/g++", "-std=c++17", - "-I/usr/include/gdk-pixbuf-2.0", - "-I/usr/include/glib-2.0", - "-I/usr/lib64/glib-2.0/include", - "-I/usr/include/sysprof-4", - "-I/usr/include/libpng16", - "-I/usr/include/libmount", - "-I/usr/include/blkid", - "-pthread", + "-I/nix/store/drrf5w7pcc5q9h4si9i8vm2hclg0zijg-libnotify-0.8.3-dev/include", + "-I/nix/store/a45ri2jgzpv6q36va2y6wq471y88hpnl-gdk-pixbuf-2.42.10-dev/include/gdk-pixbuf-2.0", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include/glib-2.0", + "-I/nix/store/k1qjs35nw1lbssg1l1xpmh0082hy7wl4-glib-2.78.4/lib/glib-2.0/include", "-c", "-o", - "commands.o", - "commands.cpp" + "build/keybinds.o", + "src/keybinds.cpp" ], "directory": "/home/boss/Documents/Coding/WM/YATwm", - "file": "/home/boss/Documents/Coding/WM/YATwm/commands.cpp", - "output": "/home/boss/Documents/Coding/WM/YATwm/commands.o" + "file": "/home/boss/Documents/Coding/WM/YATwm/src/keybinds.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/build/keybinds.o" + }, + { + "arguments": [ + "/nix/store/9bv7dcvmfcjnmg5mnqwqlq2wxfn8d7yi-gcc-wrapper-13.2.0/bin/g++", + "-std=c++17", + "-I/nix/store/drrf5w7pcc5q9h4si9i8vm2hclg0zijg-libnotify-0.8.3-dev/include", + "-I/nix/store/a45ri2jgzpv6q36va2y6wq471y88hpnl-gdk-pixbuf-2.42.10-dev/include/gdk-pixbuf-2.0", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include", + "-I/nix/store/s0nl17v1827bl7qyjgkkar90c2a40ykb-glib-2.78.4-dev/include/glib-2.0", + "-I/nix/store/k1qjs35nw1lbssg1l1xpmh0082hy7wl4-glib-2.78.4/lib/glib-2.0/include", + "-c", + "-o", + "build/commands.o", + "src/commands.cpp" + ], + "directory": "/home/boss/Documents/Coding/WM/YATwm", + "file": "/home/boss/Documents/Coding/WM/YATwm/src/commands.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/build/commands.o" } ] diff --git a/config.cpp b/config.cpp deleted file mode 100644 index 3af2491..0000000 --- a/config.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "config.h" -#include "commands.h" -#include "error.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//Just for testing -#include - -using std::string; - -// For testing -using std::cout, std::endl; - -const void Config::gapsCmd(const CommandArg* argv) -{ - gaps = argv[0].num; -} - -const void Config::outerGapsCmd(const CommandArg* argv) -{ - outerGaps = argv[0].num; -} - -const void Config::logFileCmd(const CommandArg* argv) -{ - logFile = argv[0].str; -} - -const void Config::addWorkspaceCmd(const CommandArg* argv) -{ - int* prefs = new int[argv[1].numArr.size]; - for(int i = 0; i < argv[1].numArr.size; i++) - { - prefs[i] = argv[1].numArr.arr[i] - 1; - } - workspaces.push_back({argv[0].str, prefs, argv[1].numArr.size}); - numWS++; -} - -const void Config::swapSuperAltCmd(const CommandArg* argv) -{ - swapSuperAlt ^= true; -} - -Config::Config(CommandsModule& commandsModule) - : commandsModule(commandsModule) -{ - //Register commands for config - commandsModule.addCommand("gaps", &Config::gapsCmd, 1, {NUM}, this); - commandsModule.addCommand("outergaps", &Config::outerGapsCmd, 1, {NUM}, this); - commandsModule.addCommand("logfile", &Config::logFileCmd, 1, {STR_REST}, this); - commandsModule.addCommand("addworkspace", &Config::addWorkspaceCmd, 2, {STR, NUM_ARR_REST}, this); - commandsModule.addCommand("swapmods", &Config::swapSuperAltCmd, 0, {}, this); -} - -std::vector Config::reloadFile() -{ - if(!loaded) - return {{CFG_ERR_NON_FATAL, "Not loaded config yet"}}; - return loadFromFile(file); -} - -std::vector Config::loadFromFile(std::string path) -{ - std::vector errs; - - file = path; - - std::ifstream config(path); - if(!config.good()) - { - config = std::ifstream("/etc/YATwm/config"); - errs.push_back({CFG_ERR_FATAL, "Using default config: /etc/YATwm/config"}); - } - - //Set defaults - gaps = 10; - outerGaps = 10; - logFile = "/tmp/yatlog.txt"; - numWS = 0; - swapSuperAlt = false; - workspaces = std::vector(); - - //Probably need something for workspaces and binds too... - - string cmd; - int line = 0; - while(getline(config, cmd)) - { - line++; - if(cmd.size() == 0) - continue; - if(cmd.at(0) == '#') - continue; - try - { - commandsModule.runCommand(cmd); - } - catch (Err e) - { - errs.push_back({e.code, "Error in config (line " + std::to_string(line) + "): " + std::to_string(e.code) + "\n\tMessage: " + e.message}); - - } - } - loaded = true; - return errs; -} - -Config::~Config() -{ - free(); -} -void Config::free() -{ - if(!loaded) - return; - for(Workspace w : workspaces) - { - delete [] w.screenPreferences; - } -} diff --git a/config.h b/config.h deleted file mode 100644 index 452db9c..0000000 --- a/config.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "commands.h" -#include -#include - -#include -#include - -struct Workspace -{ - std::string name; - int* screenPreferences; - int screenPreferencesc; -}; - -#define COMMAND(X) \ - const void X (const CommandArg* argv) - -class Config -{ -public: - Config(CommandsModule& commandsModule); - ~Config(); - void free(); - - std::vector loadFromFile(std::string path); - std::vector reloadFile(); - - // Main - int gaps; - int outerGaps; - std::string logFile; - - // Workspaces - std::vector workspaces; - int numWS; - bool loaded = false; - - // Binds - bool swapSuperAlt; - - // Config Commands - COMMAND(gapsCmd); - COMMAND(outerGapsCmd); - COMMAND(logFileCmd); - COMMAND(addWorkspaceCmd); - COMMAND(swapSuperAltCmd); - -private: - CommandsModule& commandsModule; - std::string file; -}; diff --git a/error.h b/error.h deleted file mode 100644 index f0a67a5..0000000 --- a/error.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -typedef unsigned int ErrCode; - -#define NOERR 0 -#define ERR_NON_FATAL 110 -#define ERR_FATAL 120 -#define CFG_ERR_NON_FATAL 210 -#define CFG_ERR_KEYBIND 211 -#define CFG_ERR_FATAL 220 -#define CMD_ERR_NON_FATAL 310 -#define CMD_ERR_NOT_FOUND 311 -#define CMD_ERR_WRONG_ARGS 312 -#define CMD_ERR_FATAL 320 -struct Err -{ - ErrCode code; - std::string message; - Err(ErrCode code, std::string message) - { - this->code = code; - this->message = message; - } -}; diff --git a/ewmh.cpp b/ewmh.cpp deleted file mode 100644 index a3cc505..0000000 --- a/ewmh.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "ewmh.h" -#include -#include -#include -#include -#include -#include - -Display** dpy_; -Window* root_; - -void initEWMH(Display** dpy, Window* root, int numWS, std::vector workspaces) -{ - dpy_ = dpy; - root_ = root; - - Atom supported[] = {XInternAtom(*dpy_, "_NET_NUMBER_OF_DESKTOPS", false), XInternAtom(*dpy_, "_NET_DESKTOP_NAMES", false), XInternAtom(*dpy_, "_NET_CLIENT_LIST", false), XInternAtom(*dpy_, "_NET_CURRENT_DESKTOP", false)}; - int wsNamesLen = numWS; //For null bytes - for(int i = 0; i < numWS; i++) - { - wsNamesLen += workspaces[i].name.length(); - } - char wsNames[wsNamesLen]; - int pos = 0; - for(int i = 0; i < numWS; i++) - { - for(char toAdd : workspaces[i].name) - { - wsNames[pos++] = toAdd; - } - wsNames[pos++] = '\0'; - } - unsigned long numDesktops = numWS; - Atom netSupportedAtom = XInternAtom(*dpy_, "_NET_SUPPORTED", false); - Atom netNumDesktopsAtom = XInternAtom(*dpy_, "_NET_NUMBER_OF_DESKTOPS", false); - Atom netDesktopNamesAtom = XInternAtom(*dpy_, "_NET_DESKTOP_NAMES", false); - Atom XA_UTF8STRING = XInternAtom(*dpy_, "UTF8_STRING", false); - XChangeProperty(*dpy_, *root_, netSupportedAtom, XA_ATOM, 32, PropModeReplace, (unsigned char*)supported, 3); - XChangeProperty(*dpy_, *root_, netDesktopNamesAtom, XA_UTF8STRING, 8, PropModeReplace, (unsigned char*)&wsNames, wsNamesLen); - XChangeProperty(*dpy_, *root_, netNumDesktopsAtom, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&numDesktops, 1); - - -} - -void updateClientList(std::map clients) -{ - Atom netClientList = XInternAtom(*dpy_, "_NET_CLIENT_LIST", false); - XDeleteProperty(*dpy_, *root_, netClientList); - - std::map::iterator cItr; - for(cItr = clients.begin(); cItr != clients.end(); cItr++) - { - XChangeProperty(*dpy_, *root_, netClientList, XA_WINDOW, 32, PropModeAppend, (unsigned char*)&cItr->second.w, 1); - } - -} - -void setWindowDesktop(Window w, int desktop) -{ - unsigned long currDesktop = desktop - 1; - Atom netWMDesktop = XInternAtom(*dpy_, "_NET_WM_DESKTOP", false); - XChangeProperty(*dpy_, w, netWMDesktop, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&currDesktop, 1); -} - -void setCurrentDesktop(int desktop) -{ - unsigned long currDesktop = desktop - 1; - Atom netCurrentDesktop = XInternAtom(*dpy_, "_NET_CURRENT_DESKTOP", false); - XChangeProperty(*dpy_, *root_, netCurrentDesktop, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&currDesktop, 1); -} - -void setFullscreen(Window w, bool fullscreen) -{ - Atom netWMState = XInternAtom(*dpy_, "_NET_WM_STATE", false); - Atom netWMStateVal; - if(fullscreen) - netWMStateVal = XInternAtom(*dpy_, "_NET_WM_STATE_FULLSCREEN", false); - else - netWMStateVal = XInternAtom(*dpy_, "", false); - XChangeProperty(*dpy_, w, netWMState, XA_ATOM, 32, PropModeReplace, (unsigned char*)&netWMStateVal, 1); - -} - -void setIPCPath(unsigned char* path, int len) -{ - Atom socketPathAtom = XInternAtom(*dpy_, "YATWM_SOCKET_PATH", false); - XChangeProperty(*dpy_, *root_, socketPathAtom, XA_STRING, 8, PropModeReplace, path, len); -} - -int getProp(Window w, char* propName, Atom* type, unsigned char** data) -{ - Atom prop_type = XInternAtom(*dpy_, propName, false); - int format; - unsigned long length; - unsigned long after; - int status = XGetWindowProperty(*dpy_, w, prop_type, - 0L, 1L, False, - AnyPropertyType, type, &format, - &length, &after, data); - return(status); -} diff --git a/ewmh.h b/ewmh.h deleted file mode 100644 index 9473d5d..0000000 --- a/ewmh.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include - -#include "structs.h" -#include "config.h" - -void initEWMH(Display** dpy, Window* root, int numWS, std::vector workspaces); - -void updateClientList(std::map clients); - -void setWindowDesktop(Window w, int desktop); - -void setCurrentDesktop(int desktop); - -void setFullscreen(Window w, bool fullscreen); - -void setIPCPath(unsigned char* path, int len); - -int getProp(Window w, char* propName, Atom* type, unsigned char** data); diff --git a/keybinds.cpp b/keybinds.cpp deleted file mode 100644 index c41452f..0000000 --- a/keybinds.cpp +++ /dev/null @@ -1,282 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "commands.h" -#include "error.h" -#include "keybinds.h" -#include "util.h" - -using std::string; - -bool Keybind::operator<(const Keybind &o) const { - if(key != o.key) - { - return key < o.key; - } - else return modifiers < o.modifiers; -} -bool Keybind::operator==(const Keybind &o) const { - return (key == o.key && modifiers == o.modifiers); -} - -KeybindsModule::KeybindsModule(CommandsModule& commandsModule, Config& cfg, Globals& globals, void (*updateMousePos)()) - :commandsModule(commandsModule), - globals(globals), - cfg(cfg) -{ - commandsModule.addCommand("bind", &KeybindsModule::bind, 2, {STR, STR_REST}, this); - commandsModule.addCommand("quitkey", &KeybindsModule::quitKey, 1, {STR}, this); - commandsModule.addCommand("bindmode", &KeybindsModule::bindMode, 1, {STR}, this); - - bindModes = { - {"normal", &KeybindsModule::normalBindMode}, - {"emacs", &KeybindsModule::emacsBindMode} - }; - bindFunc = &KeybindsModule::normalBindMode; - - this->updateMousePos = updateMousePos; - keyMaps.insert({0, std::map()}); -} - -void KeybindsModule::changeMap(int newMapID) -{ - if(currentMapID == newMapID) - return; - if(currentMapID != 0) - XUngrabKeyboard(globals.dpy, CurrentTime); - XUngrabButton(globals.dpy, AnyKey, AnyModifier, globals.root); - currentMapID = newMapID; - if(newMapID == 0) - { - for(std::pair pair : getKeymap(currentMapID)) - { - Keybind bind = pair.first; - XGrabKey(globals.dpy, bind.key, bind.modifiers, globals.root, false, GrabModeAsync, GrabModeAsync); - } - } - else - { - XGrabKeyboard(globals.dpy, globals.root, false, GrabModeAsync, GrabModeAsync, CurrentTime); - } -} - -const void KeybindsModule::handleKeypress(XKeyEvent e) -{ - if(e.same_screen!=1) return; - // cout << "Key Pressed" << endl; - // cout << "\tState: " << e.state << endl; - // cout << "\tCode: " << XKeysymToString(XKeycodeToKeysym(globals.dpy, e.keycode, 0)) << endl; - updateMousePos(); - - const unsigned int masks = ShiftMask | ControlMask | Mod1Mask | Mod4Mask; - Keybind k = {(KeyCode)e.keycode, e.state & masks}; - if(k == exitBind) - { - changeMap(0); - } - else if(getKeymap(currentMapID).count(k) > 0) - { - KeyFunction& c = getKeymap(currentMapID).find(k)->second; - if(getKeymap(c.mapID).size() == 0) - { - commandsModule.runCommand(c.command); - changeMap(0); - } - else - { - XUngrabButton(globals.dpy, AnyKey, AnyModifier, globals.root); - changeMap(c.mapID); - } - } - else if(std::find(std::begin(ignoredKeys), std::end(ignoredKeys), e.keycode) == std::end(ignoredKeys)) - { - changeMap(0); - } -} - -bool isUpper(const std::string& s) { - return std::all_of(s.begin(), s.end(), [](unsigned char c){ return std::isupper(c); }); -} - -const void KeybindsModule::bindMode(const CommandArg* argv) -{ - if(bindModes.count(argv[0].str) < 1) - { - throw Err(CFG_ERR_KEYBIND, "Bind mode: " + string(argv[0].str) + " does not exist"); - } - else - { - bindFunc = bindModes.find(argv[0].str)->second; - } -} - -Keybind KeybindsModule::getKeybind(std::string bindString) -{ - return (this->*bindFunc)(bindString); -} - -const Keybind KeybindsModule::normalBindMode(string bindString) -{ - std::vector keys = split(bindString, '+'); - Keybind bind; - bind.modifiers = 0; - for(string key : keys) - { - if(key == "mod") - { - bind.modifiers |= Mod4Mask >> 3 * cfg.swapSuperAlt; - } - else if(key == "alt") - { - bind.modifiers |= Mod1Mask << 3 * cfg.swapSuperAlt; - } - else if(key == "shift") - { - bind.modifiers |= ShiftMask; - } - else if(key == "control") - { - bind.modifiers |= ControlMask; - } - else - { - if(isUpper(key)) - { - bind.modifiers |= ShiftMask; - } - KeySym s = XStringToKeysym(key.c_str()); - if(s == NoSymbol) - { - throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!"); - } - bind.key = XKeysymToKeycode(globals.dpy, s); - } - } - if(!bind.key) - throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!"); - return bind; -} - -const Keybind KeybindsModule::emacsBindMode(string bindString) -{ - Keybind bind; - bind.modifiers = 0; - - const std::regex keyRegex("^(?:([CMs])-)?(?:([CMs])-)?(?:([CMs])-)?([^\\s]|(SPC|ESC|RET|))$"); - std::smatch keyMatch; - if(std::regex_match(bindString, keyMatch, keyRegex)) - { - for (int i = 1; i < 3; i++) - { - std::ssub_match modifierMatch = keyMatch[i]; - if(modifierMatch.matched) - { - std::string modifier = modifierMatch.str(); - if(modifier == "s") - { - bind.modifiers |= Mod4Mask >> 3 * cfg.swapSuperAlt; - } - else if(modifier == "M") - { - bind.modifiers |= Mod1Mask << 3 * cfg.swapSuperAlt; - } - else if(modifier == "C") - { - bind.modifiers |= ControlMask; - } - } - } - } - KeySym keySym = XStringToKeysym(keyMatch[4].str().c_str()); - - if(isUpper(keyMatch[4].str().c_str()) && keySym != NoSymbol) - { - bind.modifiers |= ShiftMask; - } - if(keySym == NoSymbol) - { - if(keyMatch[4].str() == "RET") - keySym = XK_Return; - else if(keyMatch[4].str() == "ESC") - keySym = XK_Escape; - else if(keyMatch[4].str() == "SPC") - keySym = XK_space; - else if(keyMatch[4].str() == "-") - keySym = XK_minus; - else if(keyMatch[4].str() == "+") - keySym = XK_plus; - else - throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid"); - } - bind.key = XKeysymToKeycode(globals.dpy, keySym); - - return bind; -} - -const void KeybindsModule::bind(const CommandArg* argv) -{ - std::vector errs = commandsModule.checkCommand(argv[1].str); - for(Err e : errs) - { - if(e.code != NOERR) - { - e.message = "Binding fail - " + e.message; - throw e; - } - } - std::vector keys = split(argv[0].str, ' '); - int currentBindingMap = 0; - for(int i = 0; i < keys.size() - 1; i++) - { - Keybind bind = getKeybind(keys[i]); - if(getKeymap(currentBindingMap).count(bind) > 0) - { - currentBindingMap = getKeymap(currentBindingMap).find(bind)->second.mapID; - } - else - { - KeyFunction newMap = {"", nextKeymapID}; - keyMaps.insert({nextKeymapID, std::map()}); - nextKeymapID++; - getKeymap(currentBindingMap).insert({bind, newMap}); - currentBindingMap = getKeymap(currentBindingMap).find(bind)->second.mapID; - } - } - Keybind bind = getKeybind(keys[keys.size() - 1]); - if(getKeymap(currentBindingMap).count(bind) <= 0) - { - KeyFunction function = {argv[1].str, nextKeymapID}; - keyMaps.insert({nextKeymapID, std::map()}); - nextKeymapID++; - getKeymap(currentBindingMap).insert({bind, function}); - if(currentBindingMap == currentMapID) - { - KeyCode c = XKeysymToKeycode(globals.dpy, bind.key); - XGrabKey(globals.dpy, c, bind.modifiers, globals.root, false, GrabModeAsync, GrabModeAsync); - } - } - else - { - throw Err(CFG_ERR_KEYBIND, "Bind is a keymap already!"); - } - // cout << "Added bind" << endl; - // cout << "\t" << argv[0].str << endl; -} - -const void KeybindsModule::quitKey(const CommandArg* argv) -{ - exitBind = getKeybind(argv[0].str); -} - -const void KeybindsModule::clearKeybinds() -{ - XUngrabButton(globals.dpy, AnyKey, AnyModifier, globals.root); - keyMaps = std::map>(); - keyMaps.insert({0, std::map()}); -} diff --git a/keybinds.h b/keybinds.h deleted file mode 100644 index a742240..0000000 --- a/keybinds.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include - -#include "commands.h" -#include "config.h" -#include "util.h" - -struct Keybind { - KeyCode key; - unsigned int modifiers; - bool operator<(const Keybind &o) const; - bool operator==(const Keybind &o) const; -}; - -struct KeyFunction -{ - std::string command; - int mapID; -}; - -#define getKeymap(X) \ - keyMaps.find(X)->second - - -class KeybindsModule -{ -public: - KeybindsModule(CommandsModule& commandsModule, Config& cfg, Globals& globals, void (*updateMousePos)()); - ~KeybindsModule() = default; - const void bind(const CommandArg* argv); - const void quitKey(const CommandArg* argv); - const void bindMode(const CommandArg* argv); - const void handleKeypress(XKeyEvent e); - const void clearKeybinds(); -private: - Keybind getKeybind(std::string bindString); - void changeMap(int newMapID); - std::map> keyMaps; - const Keybind emacsBindMode(std::string bindString); - const Keybind normalBindMode(std::string bindString); - std::map bindModes; - const Keybind(KeybindsModule::* bindFunc)(std::string bindString); - // Modifier keys to ignore when canceling a keymap - KeyCode ignoredKeys[8] = {50, 37, 133, 64, 62, 105, 134, 108}; - int currentMapID = 0; - int nextKeymapID = 1; - Keybind exitBind = {42, 0x40}; - CommandsModule& commandsModule; - Config& cfg; - Globals& globals; - void (*updateMousePos)(); -}; diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 1f3edc2..0000000 --- a/main.cpp +++ /dev/null @@ -1,1159 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "IPC.h" -#include "commands.h" -#include "keybinds.h" -#include "structs.h" -#include "config.h" -#include "util.h" -#include "ewmh.h" -#include "error.h" - -using std::cout; -using std::string; -using std::endl; -using std::map; -using std::pair; -using std::vector; - -std::ofstream yatlog; -std::time_t timeNow; -std::tm *now; -char nowString[80]; - -#define log(x) \ - updateTime(); \ - yatlog << nowString << x << std::endl - -Display* dpy; -Window root; - -Globals globals = {dpy, root}; - -void updateMousePos(); - -CommandsModule commandsModule; -Config cfg(commandsModule); -KeybindsModule keybindsModule(commandsModule, cfg, globals, &updateMousePos); -IPCModule ipc(commandsModule, cfg, globals); - -int sW, sH; -int bH; -TileDir nextDir = horizontal; - -bool keepGoing = true; - -map clients; -int currClientID = 0; -map frames; -int currFrameID = 1; -map frameIDS; - -ScreenInfo* screens; -int* focusedWorkspaces; -int focusedScreen = 0; -int nscreens; -int mX, mY; - -#define getClient(c) clients.find(c)->second -#define getFrame(f) frames.find(f)->second -#define getFrameID(w) frameIDS.find(w)->second - -Window bar; - -int currWS = 1; - - -// Usefull functions -int FFCF(int sID); -void detectScreens(); -void focusRoot(int root); -void handleConfigErrs(vector cfgErrs); -void updateTime(); - -void configureRequest(XConfigureRequestEvent e); -void mapRequest(XMapRequestEvent e); -void destroyNotify(XDestroyWindowEvent e); -void enterNotify(XEnterWindowEvent e); -void clientMessage(XClientMessageEvent e); - -static int OnXError(Display* display, XErrorEvent* e); - -// Tiling -// Call this one to tile everything (it does all the fancy stuff trust me just call this one) -void tileRoots(); -// Call this one to until everything (it handles multiple monitors) -void untileRoots(); -// This is to be called by tileRoots, it takes in the x, y, w, and h of where it's allowed to tile windows to, and returns the ID of a fullscreen client if one is found, or noID (-1) if none are found -int tile(int frameID, int x, int y, int w, int h); -// This is to be called by tileRoots, it takes in a frameID and recursively unmaps all its children -void untile(int frameID); - -// Usefull functions -int FFCF(int sID) -{ - if(frames.find(sID)->second.isClient) - return sID; - return FFCF(frames.find(sID)->second.subFrameIDs[0]); -} -void detectScreens() -{ - delete[] screens; - delete[] focusedWorkspaces; - log("Detecting screens: "); - XRRMonitorInfo* monitors = XRRGetMonitors(dpy, root, true, &nscreens); - log("\t" << nscreens << " monitors"); - screens = new ScreenInfo[nscreens]; - focusedWorkspaces = new int[nscreens]; - for(int i = 0; i < nscreens; i++) - { - focusedWorkspaces[i] = i * 5 + 1; - char* name = XGetAtomName(dpy, monitors[i].name); - screens[i] = {name, monitors[i].x, monitors[i].y, monitors[i].width, monitors[i].height}; - log("\tMonitor " << i + 1 << " - " << screens[i].name); - log("\t\tx: " << screens[i].x << ", y: " << screens[i].y); - log("\t\tw: " << screens[i].w << ", h: " << screens[i].h); - XFree(name); - } - for(int i = 0; i < cfg.workspaces.size(); i++) - { - if(cfg.workspaces[i].screenPreferences[0] < nscreens && focusedWorkspaces[cfg.workspaces[i].screenPreferences[0]] == 0) - { - //focusedWorkspaces[screenPreferences[i][0]] = i+1; - } - } - XFree(monitors); -} -void updateMousePos() -{ - Window rootRet, childRet; - int rX, rY, cX, cY; - unsigned int maskRet; - XQueryPointer(dpy, root, &rootRet, &childRet, &rX, &rY, &cX, &cY, &maskRet); - mX = rX; - mY = rY; -} -int getClientChild(int fID) -{ - if(getFrame(fID).isClient) - return fID; - else - return getClientChild(getFrame(fID).subFrameIDs[0]); -} -void focusRoot(int root) -{ - //log("Focusing root: " << root); - if(getFrame(root).subFrameIDs.size() == 0) - { - //log("\tRoot has no children"); - XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); - return; - } - int client = getFrame(getClientChild(root)).cID; - Window w = getClient(client).w; - //log("\tFocusing window: " << w); - XSetInputFocus(dpy, w, RevertToPointerRoot, CurrentTime); -} -void handleConfigErrs(vector cfgErrs) -{ - for(Err cfgErr : cfgErrs) - { - if(cfgErr.code == CFG_ERR_FATAL) - { - log("YATwm fatal error (Code " << cfgErr.code << ")\n" << cfgErr.message); - std::string title = "YATwm fatal config error (Code " + std::to_string(cfgErr.code) + ")"; - std::string body = cfgErr.message; - NotifyNotification* n = notify_notification_new(title.c_str(), - body.c_str(), - 0); - notify_notification_set_timeout(n, 10000); - if(!notify_notification_show(n, 0)) - { - log("notification failed"); - } - } - else - { - log("YATwm non fatal error (Code " << cfgErr.code << ")\n" << cfgErr.message); - std::string title = "YATwm non fatal config error (Code " + std::to_string(cfgErr.code) + ")"; - std::string body = "Check logs for more information"; - NotifyNotification* n = notify_notification_new(title.c_str(), - body.c_str(), - 0); - notify_notification_set_timeout(n, 10000); - if(!notify_notification_show(n, 0)) - { - log("notification failed"); - } - } - } -} -void updateTime() -{ - timeNow = std::time(0); - now = std::localtime(&timeNow); - strftime(nowString, sizeof(nowString), "[%H:%M:%S] ", now); -} - -//Keybind commands -const void exit(const CommandArg* argv) -{ - keepGoing = false; -} -const void spawn(const CommandArg* argv) -{ - if(fork() == 0) - { - const std::string argsStr = argv[0].str; - vector args = split(argsStr, ' '); - char** execvpArgs = new char*[args.size()]; - for(int i = 0; i < args.size(); i++) - { - execvpArgs[i] = strdup(args[i].c_str()); - } - int null = open("/dev/null", O_WRONLY); - dup2(null, 0); - dup2(null, 1); - dup2(null, 2); - execvp(execvpArgs[0], execvpArgs); - exit(0); - } -} -const void spawnOnce(const CommandArg* argv) -{ - if(cfg.loaded) - return; - else spawn(argv); -} -const void toggle(const CommandArg* argv) -{ - nextDir = nextDir = (nextDir==horizontal)? vertical : horizontal; -} -const void kill(const CommandArg* argv) -{ - Window w; - int revertToReturn; - XGetInputFocus(dpy, &w, &revertToReturn); - Atom* supported_protocols; - int num_supported_protocols; - if (XGetWMProtocols(dpy, - w, - &supported_protocols, - &num_supported_protocols) && - (std::find(supported_protocols, - supported_protocols + num_supported_protocols, - XInternAtom(dpy, "WM_DELETE_WINDOW", false)) != - supported_protocols + num_supported_protocols)) { - // 1. Construct message. - XEvent msg; - memset(&msg, 0, sizeof(msg)); - msg.xclient.type = ClientMessage; - msg.xclient.message_type = XInternAtom(dpy, "WM_PROTOCOLS", false); - msg.xclient.window = w; - msg.xclient.format = 32; - msg.xclient.data.l[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", false); - // 2. Send message to window to be closed. - cout << "Nice kill\n"; - XSendEvent(dpy, w, false, 0, &msg); - } else { - cout << "Mean kill\n"; - XKillClient(dpy, w); - } -} -// Took this out as it is used commonly -void cWS(int newWS) -{ - int prevWS = currWS; - - currWS = newWS; - if(prevWS == currWS) - return; - untileRoots(); - - //log("Changing WS with keybind"); - - for(int i = 0; i < cfg.workspaces[newWS - 1].screenPreferencesc; i++) - { - if(nscreens > cfg.workspaces[newWS - 1].screenPreferences[i]) - { - int screen = cfg.workspaces[newWS - 1].screenPreferences[i]; - //log("Found screen (screen " << screenPreferences[arg.num - 1][i] << ")"); - prevWS = focusedWorkspaces[screen]; - //log("Changed prevWS"); - focusedWorkspaces[screen] = newWS; - //log("Changed focusedWorkspaces"); - if(focusedScreen != screen) - { - focusedScreen = screen; - XWarpPointer(dpy, root, root, 0, 0, 0, 0, screens[screen].x + screens[screen].w/2, screens[screen].y + screens[screen].h/2); - } - //log("Changed focusedScreen"); - break; - } - } - - //log("Finished changes"); - - //log(prevWS); - // LOOK: what is this for????? - if(prevWS < 1 || prevWS > cfg.workspaces.size()) - { - //untile(prevWS); - } - //log("Untiled"); - //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); - tileRoots(); - //log("Roots tiled"); - XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); - - cout << focusedWorkspaces[0] << endl; - - //EWMH - setCurrentDesktop(currWS); -} -const void changeWS(const CommandArg* argv) -{ - cWS(argv[0].num); -} -const void wToWS(const CommandArg* argv) -{ - Window focusedWindow; - int revertToReturn; - XGetInputFocus(dpy, &focusedWindow, &revertToReturn); - if(focusedWindow == root) - return; - - int fID = frameIDS.find(focusedWindow)->second; - //TODO: make floating windows move WS - if(clients.find(frames.find(fID)->second.cID)->second.floating) - return; - vector& pSF = frames.find(frames.find(fID)->second.pID)->second.subFrameIDs; - for(int i = 0; i < pSF.size(); i++) - { - if(pSF[i] == fID) - { - //Frame disolve - pSF.erase(pSF.begin() + i); - int pID = frames.find(fID)->second.pID; - if(pSF.size() < 2 && !frames.find(pID)->second.isRoot) - { - //Erase parent frame - int lastChildID = frames.find(frames.find(pID)->second.subFrameIDs[0])->second.ID; - int parentParentID = frames.find(pID)->second.pID; - vector& parentParentSubFrameIDs = frames.find(parentParentID)->second.subFrameIDs; - for(int j = 0; j < parentParentSubFrameIDs.size(); j++) - { - if(parentParentSubFrameIDs[j] == pID) - { - parentParentSubFrameIDs[j] = lastChildID; - frames.find(lastChildID)->second.pID = parentParentID; - frames.erase(pID); - break; - } - } - } - - break; - } - } - frames.find(fID)->second.pID = argv[0].num; - frames.find(argv[0].num)->second.subFrameIDs.push_back(fID); - - //EWMH - setWindowDesktop(focusedWindow, argv[0].num); - - XUnmapWindow(dpy, focusedWindow); - //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); - untileRoots(); - tileRoots(); - XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); -} -int dirFind(int fID, MoveDir dir) -{ - vector& pSF = frames.find(frames.find(fID)->second.pID)->second.subFrameIDs; - TileDir pDir = frames.find(frames.find(fID)->second.pID)->second.dir; - - int i = 0; - for(int f : pSF) - { - if(f == fID) - { - break; - } - i++; - } - - if(pDir == vertical) - { - switch(dir) - { - case UP: i--; break; - case DOWN: i++; break; - case LEFT: return (frames.find(fID)->second.pID > cfg.numWS)? dirFind(frames.find(fID)->second.pID, dir) : fID; - case RIGHT: return (frames.find(fID)->second.pID > cfg.numWS)? dirFind(frames.find(fID)->second.pID, dir) : fID; - } - } - else if(pDir == horizontal) - { - switch(dir) - { - case LEFT: i--; break; - case RIGHT: i++; break; - case UP: return (frames.find(fID)->second.pID > cfg.numWS)? dirFind(frames.find(fID)->second.pID, dir) : fID; - case DOWN: return (frames.find(fID)->second.pID > cfg.numWS)? dirFind(frames.find(fID)->second.pID, dir) : fID; - } - } - if(i < 0) - i = pSF.size() - 1; - if(i == pSF.size()) - i = 0; - - return pSF[i]; -} -const void focChange(const CommandArg* argv) -{ - Window focusedWindow; - int revertToReturn; - XGetInputFocus(dpy, &focusedWindow, &revertToReturn); - if(focusedWindow == root) - return; - - int fID = frameIDS.find(focusedWindow)->second; - int nID = dirFind(fID, argv[0].dir); - int fNID = FFCF(nID); - Window w = clients.find(frames.find(fNID)->second.cID)->second.w; - XSetInputFocus(dpy, w, RevertToPointerRoot, CurrentTime); -} -const void wMove(const CommandArg* argv) -{ - Window focusedWindow; - int revertToReturn; - XGetInputFocus(dpy, &focusedWindow, &revertToReturn); - if(focusedWindow == root) - return; - - int fID = frameIDS.find(focusedWindow)->second; - if(clients.find(frames.find(fID)->second.cID)->second.floating) - return; - int nID = dirFind(fID, argv[0].dir); - int fNID = FFCF(nID); - int pID = frames.find(fNID)->second.pID; - int oPID = frames.find(fID)->second.pID; - - vector& pSF = frames.find(pID)->second.subFrameIDs; - vector& oPSF = frames.find(oPID)->second.subFrameIDs; - - for(int i = 0; i < frames.find(oPID)->second.subFrameIDs.size(); i++) - { - if(oPSF[i] != fID) - continue; - - if(pID!=oPID) - { - //Frame dissolve - oPSF.erase(oPSF.begin() + i); - if(oPSF.size() < 2 && !frames.find(oPID)->second.isRoot) - { - //Erase parent frame - int lastChildID = frames.find(frames.find(oPID)->second.subFrameIDs[0])->second.ID; - int parentParentID = frames.find(oPID)->second.pID; - vector& parentParentSubFrameIDs = frames.find(parentParentID)->second.subFrameIDs; - for(int j = 0; j < parentParentSubFrameIDs.size(); j++) - { - if(parentParentSubFrameIDs[j] == oPID) - { - parentParentSubFrameIDs[j] = lastChildID; - frames.find(lastChildID)->second.pID = parentParentID; - frames.erase(oPID); - break; - } - } - } - - frames.find(fID)->second.pID = pID; - pSF.push_back(fID); - } - else - { - if(frames.find(pID)->second.dir == vertical) - { - if(argv[0].dir == LEFT || argv[0].dir == RIGHT) - return; - } - else - { - if(argv[0].dir == UP || argv[0].dir == DOWN) - return; - } - - int offset; - if(argv[0].dir == UP || argv[0].dir == LEFT) - offset = -1; - else - offset = 1; - - int swapPos = i + offset; - - if(swapPos == pSF.size()) - swapPos = 0; - else if(swapPos == -1) - swapPos = pSF.size() - 1; - - std::swap(pSF[i], pSF[swapPos]); - } - untileRoots(); - tileRoots(); - //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); - XSetInputFocus(dpy, focusedWindow, RevertToPointerRoot, CurrentTime); - return; - } - XSetInputFocus(dpy, focusedWindow, RevertToPointerRoot, CurrentTime); -} -const void bashSpawn(const CommandArg* argv) -{ - if(fork() == 0) - { - int null = open("/dev/null", O_WRONLY); - dup2(null, 0); - dup2(null, 1); - dup2(null, 2); - system(argv[0].str); - exit(0); - } -} -const void bashSpawnOnce(const CommandArg* argv) -{ - if(cfg.loaded) - return; - else bashSpawn(argv); -} -const void reload(const CommandArg* argv) -{ - detectScreens(); - - //Clear keybinds - keybindsModule.clearKeybinds(); - - //Load config again - vector cfgErr = cfg.reloadFile(); - //Error check - handleConfigErrs(cfgErr); - - //Re tile - untileRoots(); - tileRoots(); -} -const void wsDump(const CommandArg* argv) -{ - log("Workspace dump:"); - for(int i = 1; i < currFrameID; i++) - { - if(getFrame(i).isClient) - { - int id = i; - while(!getFrame(id).isRoot) - { - id=getFrame(id).pID; - } - log("\tClient with ID: " << getClient(getFrame(i).cID).w << ", on worskapce " << id); - } - } -} -const void nextMonitor(const CommandArg* argv) -{ - focusedScreen++; - if(focusedScreen >= nscreens) - focusedScreen = 0; - - XWarpPointer(dpy, root, root, 0, 0, 0, 0, screens[focusedScreen].x + screens[focusedScreen].w/2, screens[focusedScreen].y + screens[focusedScreen].h/2); - focusRoot(focusedWorkspaces[focusedScreen]); -} -const void fullscreen(const CommandArg* arg) -{ - Window focusedWindow; - int focusedRevert; - XGetInputFocus(dpy, &focusedWindow, &focusedRevert); - - int fID = getFrameID(focusedWindow); - int cID = getFrame(fID).cID; - getClient(cID).fullscreen ^= true; - tileRoots(); - setFullscreen(focusedWindow, getClient(cID).fullscreen); -} - -void configureRequest(XConfigureRequestEvent e) -{ - XWindowChanges changes; - changes.x = e.x; - changes.y = e.y; - changes.width = e.width; - changes.height = e.height; - changes.border_width = e.border_width; - changes.sibling = e.above; - changes.stack_mode = e.detail; - XConfigureWindow(dpy, e.window, (unsigned int) e.value_mask, &changes); - log("Configure request: " << e.window); - //XSetInputFocus(dpy, e.window, RevertToNone, CurrentTime); - //tileRoots(); -} - -void mapRequest(XMapRequestEvent e) -{ - XMapWindow(dpy, e.window); - - XTextProperty name; - bool gotName = XGetWMName(dpy, e.window, &name); - XWindowAttributes attr; - XGetWindowAttributes(dpy, e.window, &attr); - if(gotName) - { - log("Mapping window: " << name.value); - } - else - { - log("Mapping window with unknown name (its probably mpv, mpv is annoying)"); - } - log("\tWindow ID: " << e.window); - - Window focusedWindow; - int revertToReturn; - int pID; - XGetInputFocus(dpy, &focusedWindow, &revertToReturn); - if(focusedWindow && focusedWindow != root && frameIDS.count(focusedWindow)>0) - { - //Use focused to determine parent - pID = frames.find(frameIDS.find(focusedWindow)->second)->second.pID; - } - else - { - Window rootRet, childRet; - int rX, rY, cX, cY; - unsigned int maskRet; - XQueryPointer(dpy, root, &rootRet, &childRet, &rX, &rY, &cX, &cY, &maskRet); - mX = rX; - mY = rY; - int monitor = 0; - for(int i = 0; i < nscreens; i++) - { - if(screens[i].x <= mX && mX < screens[i].x + screens[i].w) - { - if(screens[i].y <= mY && mY < screens[i].y + screens[i].h) - { - monitor = i; - } - } - } - pID = focusedWorkspaces[monitor]; - focusedScreen = monitor; - /* - if(mX == rX && mY == rY) - { - //Use focused screen - log("\tFocused screen is: " << focusedScreen); - } - else - { - //Use mouse - //TODO: Make this find the monitor - log("\tMouse is at x: " << rX << ", y: " << rY); - mX = rX; - mY = rY; - } - */ - } - - unsigned char* data; - Atom type; - int status = getProp(e.window, "_NET_WM_WINDOW_TYPE", &type, &data); - if (status == Success && type != None && ((Atom*)data)[0] == XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", false)) - { - log("\tWindow was bar"); - bH = attr.height; - bar = e.window; - XFree(data); - return; - } - XFree(data); - - - - - XSelectInput(dpy, e.window, EnterWindowMask); - - //Make client - Client c = {currClientID, e.window, false, false}; - currClientID++; - - //Add to clients map - clients.insert(pair(c.ID, c)); - - //Make frame - //pID = (frameIDS.count(focusedWindow)>0)? frames.find(frameIDS.find(focusedWindow)->second)->second.pID : currWS; - vector v; - vector floating; - Frame f = {currFrameID, pID, true, c.ID, noDir, v, false, floating}; - currFrameID++; - - - //Add ID to frameIDS map - frameIDS.insert(pair(e.window, f.ID)); - - status = getProp(e.window, "_NET_WM_STATE", &type, &data); - if(status == Success && type!=None && (((Atom*)data)[0] == XInternAtom(dpy, "_NET_WM_STATE_MODAL", false) || ((Atom*)data)[0] == XInternAtom(dpy, "_NET_WM_STATE_ABOVE", false))) - { - cout << "Floating" << endl; - clients.find(c.ID)->second.floating = true; - frames.find(pID)->second.floatingFrameIDs.push_back(f.ID); - frames.insert(pair(f.ID, f)); - setWindowDesktop(e.window, currWS); - updateClientList(clients); - XFree(data); - //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); - tileRoots(); - return; - } - XFree(data); - - //Check how to add - if(nextDir == frames.find(pID)->second.dir || frameIDS.count(focusedWindow)==0) - { - //Add to focused parent - frames.find(pID)->second.subFrameIDs.push_back(f.ID); - } - else - { - //Get parent sub frames for later use - vector& pS = frames.find(pID)->second.subFrameIDs; - - //Get index of focused frame in parent sub frames - int index; - for(index = 0; index < pS.size(); index++) - { - if(pS[index] == frames.find(frameIDS.find(focusedWindow)->second)->second.ID) - break; - } - - //Make new frame - vector v; - v.push_back(frames.find(frameIDS.find(focusedWindow)->second)->second.ID); - v.push_back(f.ID); - Frame pF = {currFrameID, pID, false, noID, nextDir, v, false, floating}; - - //Update the IDS - f.pID = currFrameID; - frames.find(frames.find(frameIDS.find(focusedWindow)->second)->second.ID)->second.pID = currFrameID; - pS[index] = currFrameID; - - currFrameID++; - - //Insert the new frame into the frames map - frames.insert(pair(pF.ID, pF)); - } - - //Add to frames map - frames.insert(pair(f.ID, f)); - - setWindowDesktop(e.window, currWS); - updateClientList(clients); - - //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); - XSetInputFocus(dpy, e.window, RevertToNone, CurrentTime); - tileRoots(); -} - -void destroyNotify(XDestroyWindowEvent e) -{ - if(frameIDS.count(e.window)<1) - return; - log("Destroy notif"); - log("\tWindow ID: " << e.window); - int fID = frameIDS.find(e.window)->second; - int pID = frames.find(fID)->second.pID; - vector& pS = frames.find(pID)->second.subFrameIDs; - if(clients.find(frames.find(fID)->second.cID)->second.floating) - { - pS = frames.find(pID)->second.floatingFrameIDs; - } - for(int i = 0; i < pS.size(); i++) - { - if(frames.find(pS[i])->second.ID == fID) - { - pS.erase(pS.begin() + i); - clients.erase(frames.find(fID)->second.cID); - frames.erase(fID); - frameIDS.erase(e.window); - - if(pS.size() < 2 && !frames.find(pID)->second.isRoot) - { - //Erase parent frame - int lastChildID = frames.find(frames.find(pID)->second.subFrameIDs[0])->second.ID; - int parentParentID = frames.find(pID)->second.pID; - vector& parentParentSubFrameIDs = frames.find(parentParentID)->second.subFrameIDs; - for(int j = 0; j < parentParentSubFrameIDs.size(); j++) - { - if(parentParentSubFrameIDs[j] == pID) - { - parentParentSubFrameIDs[j] = lastChildID; - frames.find(lastChildID)->second.pID = parentParentID; - frames.erase(pID); - break; - } - } - } - break; - } - } - XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); - //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); - tileRoots(); - - updateClientList(clients); -} -void enterNotify(XEnterWindowEvent e) -{ - //log(e.xcrossing.x); - //Cancel if crossing into root - if(e.window == root) - return; - - XWindowAttributes attr; - XGetWindowAttributes(dpy, e.window, &attr); - int monitor = 0; - for(int i = 0; i < nscreens; i++) - { - if(screens[i].x <= attr.x && attr.x < screens[i].x + screens[i].w) - { - if(screens[i].y <= attr.y && attr.y < screens[i].y + screens[i].h) - { - monitor = i; - } - } - } - focusedScreen = monitor; - XSetInputFocus(dpy, e.window, RevertToNone, CurrentTime); -} -void clientMessage(XClientMessageEvent e) -{ - char* name = XGetAtomName(dpy, e.message_type); - log("Client message: " << name); - if(e.message_type == XInternAtom(dpy, "_NET_CURRENT_DESKTOP", false)) - { - cWS(e.data.l[0] + 1); - /* - //Change desktop - int nextWS = (long)e.data.l[0] + 1; - int prevWS = currWS; - currWS = nextWS; - - if(prevWS == currWS) - return; - - untile(prevWS); - tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); - XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); - - //EWMH - setCurrentDesktop(currWS); - */ - } - else if(e.message_type == XInternAtom(dpy, "_NET_WM_STATE", false)) - { - if((Atom)e.data.l[0] == 0) - log("\tremove"); - if((Atom)e.data.l[0] == 1) - log("\ttoggle"); - if((Atom)e.data.l[0] == 2) - log("\tadd"); - char* prop1 = XGetAtomName(dpy, (Atom)e.data.l[1]); - if((Atom)e.data.l[1] == XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", false)) - { - int fID = getFrameID(e.window); - int cID = getFrame(fID).cID; - getClient(cID).fullscreen = (Atom) e.data.l[0] > 0; - setFullscreen(e.window, (Atom) e.data.l[0] > 0); - tileRoots(); - } - XFree(prop1); - } - XFree(name); -} - -static int OnXError(Display* display, XErrorEvent* e) -{ - char* error = new char[50]; - XGetErrorText(dpy, e->type, error, 50); - log("XError " << error); - delete[] error; - return 0; -} - -void tileRoots() -{ - for(int i = 0; i < nscreens; i++) - { - int fullscreenClientID = tile(focusedWorkspaces[i], screens[i].x + cfg.outerGaps, screens[i].y + cfg.outerGaps, screens[i].w - cfg.outerGaps*2, screens[i].h - cfg.outerGaps*2 - bH); - if(fullscreenClientID!=noID) - { - untile(focusedWorkspaces[i]); - Client c = getClient(fullscreenClientID); - XMapWindow(dpy, c.w); - XMoveWindow(dpy, c.w, - screens[i].x, screens[i].y); - XResizeWindow(dpy, c.w, - screens[i].w, screens[i].h); - } - } -} -void untileRoots() -{ - for(int i = 0; i < nscreens; i++) - { - untile(focusedWorkspaces[i]); - } -} -int tile(int frameID, int x, int y, int w, int h) -{ - for(int fID : frames.find(frameID)->second.floatingFrameIDs) - { - Window w = clients.find(frames.find(fID)->second.cID)->second.w; - XMapWindow(dpy, w); - } - TileDir dir = frames.find(frameID)->second.dir; - int i = 0; - vector& subFrameIDs = frames.find(frameID)->second.subFrameIDs; - for(int fID : subFrameIDs) - { - Frame f = frames.find(fID)->second; - int wX = (dir==horizontal) ? x + i * (w/subFrameIDs.size()) : x; - int wY = (dir==vertical) ? y + i * (h/subFrameIDs.size()) : y; - int wW = (dir==horizontal) ? w/subFrameIDs.size() : w; - int wH = (dir==vertical) ? h/subFrameIDs.size() : h; - i++; - if(i==subFrameIDs.size()) - { - wW = (dir==horizontal) ? w - (wX - x) : w; - wH = (dir==vertical) ? h - (wY - y) : h; - } - if(!f.isClient) - { - int fullscreenClientID = tile(fID, wX, wY, wW, wH); - if(fullscreenClientID == noID) - return fullscreenClientID; - continue; - } - Client c = clients.find(f.cID)->second; - if(c.fullscreen) - return c.ID; - wX += cfg.gaps; - wY += cfg.gaps; - wW -= cfg.gaps * 2; - wH -= cfg.gaps * 2; - XMapWindow(dpy, c.w); - XMoveWindow(dpy, c.w, - wX, wY); - XResizeWindow(dpy, c.w, - wW, wH); - } - return noID; -} - -void untile(int frameID) -{ - for(int fID : frames.find(frameID)->second.floatingFrameIDs) - { - Window w = clients.find(frames.find(fID)->second.cID)->second.w; - XUnmapWindow(dpy, w); - } - vector& subFrameIDs = frames.find(frameID)->second.subFrameIDs; - TileDir dir = frames.find(frameID)->second.dir; - for(int fID : subFrameIDs) - { - Frame f = frames.find(fID)->second; - if(!f.isClient) - { - untile(fID); - continue; - } - Client c = clients.find(f.cID)->second; - XUnmapWindow(dpy, c.w); - } -} - -int main(int argc, char** argv) -{ - if(argc > 1) - { - if(strcmp(argv[1], "--version") == 0) - { - const char* version = - "YATwm for X\n" - "version 0.1.0"; - cout << version << endl; - return 0; - } - } - //Important init stuff - mX = mY = 0; - dpy = XOpenDisplay(nullptr); - root = Window(DefaultRootWindow(dpy)); - - // Adding commands - commandsModule.addCommand("exit", exit, 0, {}); - commandsModule.addCommand("spawn", spawn, 1, {STR_REST}); - commandsModule.addCommand("spawnOnce", spawnOnce, 1, {STR_REST}); - commandsModule.addCommand("toggle", toggle, 0, {}); - commandsModule.addCommand("kill", kill, 0, {}); - commandsModule.addCommand("changeWS", changeWS, 1, {NUM}); - commandsModule.addCommand("wToWS", wToWS, 1, {NUM}); - commandsModule.addCommand("focChange", focChange, 1, {MOVDIR}); - commandsModule.addCommand("bashSpawn", bashSpawn, 1, {STR_REST}); - commandsModule.addCommand("bashSpawnOnce", bashSpawnOnce, 1, {STR_REST}); - commandsModule.addCommand("reload", reload, 0, {}); - commandsModule.addCommand("wsDump", wsDump, 0, {}); - commandsModule.addCommand("nextMonitor", nextMonitor, 0, {}); - commandsModule.addCommand("fullscreen", fullscreen, 0, {}); - - //Config - std::vector cfgErr; - - char* confDir = getenv("XDG_CONFIG_HOME"); - if(confDir != NULL) - { - cfgErr = cfg.loadFromFile(string(confDir) + "/YATwm/config"); - } - else - { - string home = getenv("HOME"); - cfgErr = cfg.loadFromFile(home + "/.config/YATwm/config"); - } - - //Log - yatlog.open(cfg.logFile, std::ios_base::app); - yatlog << "\n" << endl; - - //Print starting message - log("-------- YATWM STARTING --------"); - - //Notifications - notify_init("YATwm"); - - //Error check config - handleConfigErrs(cfgErr); - - screens = new ScreenInfo[1]; - focusedWorkspaces = new int[1]; - detectScreens(); - - int screenNum = DefaultScreen(dpy); - sW = DisplayWidth(dpy, screenNum); - sH = DisplayHeight(dpy, screenNum); - - //XSetErrorHandler(OnXError); - XSelectInput(dpy, root, SubstructureRedirectMask | SubstructureNotifyMask | KeyPressMask | EnterWindowMask); - - XDefineCursor(dpy, root, XCreateFontCursor(dpy, XC_top_left_arrow)); - //EWMH - initEWMH(&dpy, &root, cfg.workspaces.size(), cfg.workspaces); - setCurrentDesktop(1); - - ipc.init(); - - for(int i = 1; i < cfg.numWS + 1; i++) - { - vector v; - Frame rootFrame = {i, noID, false, noID, horizontal, v, true}; - frames.insert(pair(i, rootFrame)); - currFrameID++; - } - - XSetInputFocus(dpy, root, RevertToNone, CurrentTime); - XWarpPointer(dpy, root, root, 0, 0, 0, 0, 960, 540); - - fd_set fdset; - int x11fd = ConnectionNumber(dpy); - FD_ZERO(&fdset); - FD_SET(x11fd, &fdset); - FD_SET(ipc.getFD(), &fdset); - - log("Begin mainloop"); - while(keepGoing) - { - FD_ZERO(&fdset); - FD_SET(x11fd, &fdset); - FD_SET(ipc.getFD(), &fdset); - int ready = select(x11fd + 1, &fdset, NULL, NULL, NULL); - if(FD_ISSET(ipc.getFD(), &fdset)) - { - ipc.doListen(); - } - if(FD_ISSET(x11fd, &fdset)) - { - XEvent e; - while(XPending(dpy)) - { - XNextEvent(dpy, &e); - - switch(e.type) - { - case KeyPress: - keybindsModule.handleKeypress(e.xkey); - break; - case ConfigureRequest: - configureRequest(e.xconfigurerequest); - break; - case MapRequest: - mapRequest(e.xmaprequest); - break; - case DestroyNotify: - destroyNotify(e.xdestroywindow); - break; - case EnterNotify: - enterNotify(e.xcrossing); - break; - case ClientMessage: - clientMessage(e.xclient); - break; - default: - // cout << "Unhandled event: " << getEventName(e.type) << endl; - break; - } - } - } - if(ready == -1) - { - cout << "E" << endl; - log("ERROR"); - } - } - - //Kill children - ipc.quitIPC(); - XCloseDisplay(dpy); -} diff --git a/makefile b/makefile index 68e0560..883bc26 100644 --- a/makefile +++ b/makefile @@ -2,9 +2,9 @@ CXX := g++ CXXFLAGS := -std=c++17 `pkg-config --cflags --libs libnotify`# -g -fsanitize=address -fno-omit-frame-pointer LINKFLAGS := -lX11 -lXrandr -OBJS_DIR := . -OUT_DIR := . -SOURCE_DIR := . +OBJS_DIR := build +OUT_DIR := out +SOURCE_DIR := src EXEC := YATwm SOURCE_FILES := $(wildcard $(SOURCE_DIR)/*.cpp) SOURCE_HEADERS := $(wildcard $(SOURCE_DIR)/*.h) @@ -12,7 +12,7 @@ OBJS := $(subst $(SOURCE_DIR),$(OBJS_DIR), $(patsubst %.cpp,%.o,$(SOURCE_FILES)) INSTALL_DIR = / $(EXEC): $(OBJS) - $(CXX) $(OBJS) $(CXXFLAGS) $(LINKFLAGS) -o $(OUT_DIR)/$(EXEC) + $(CXX) $(OBJS) $(CXXFLAGS) $(LINKFLAGS) -o $(EXEC) $(OBJS_DIR)/%.o : $(SOURCE_DIR)/%.cpp $(CXX) $(CXXFLAGS) -c $< -o $@ @@ -39,4 +39,4 @@ $(OBJS_DIR)/ipc.o: $(SOURCE_DIR)/ipc.cpp $(SOURCE_DIR)/ipc.h $(SOURCE_DIR)/comma clean: rm $(OBJS_DIR)/*.o - rm $(OUT_DIR)/$(EXEC) + rm $(EXEC) diff --git a/old.compile_commands.json b/old.compile_commands.json new file mode 100644 index 0000000..3997f42 --- /dev/null +++ b/old.compile_commands.json @@ -0,0 +1,128 @@ +[ + { + "arguments": [ + "/usr/bin/g++", + "-std=c++17", + "-I/usr/include/gdk-pixbuf-2.0", + "-I/usr/include/glib-2.0", + "-I/usr/lib64/glib-2.0/include", + "-I/usr/include/sysprof-4", + "-I/usr/include/libpng16", + "-I/usr/include/libmount", + "-I/usr/include/blkid", + "-pthread", + "-c", + "-o", + "ewmh.o", + "ewmh.cpp" + ], + "directory": "/home/boss/Documents/Coding/WM/YATwm", + "file": "/home/boss/Documents/Coding/WM/YATwm/ewmh.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/ewmh.o" + }, + { + "arguments": [ + "/usr/bin/g++", + "-std=c++17", + "-I/usr/include/gdk-pixbuf-2.0", + "-I/usr/include/glib-2.0", + "-I/usr/lib64/glib-2.0/include", + "-I/usr/include/sysprof-4", + "-I/usr/include/libpng16", + "-I/usr/include/libmount", + "-I/usr/include/blkid", + "-pthread", + "-c", + "-o", + "main.o", + "main.cpp" + ], + "directory": "/home/boss/Documents/Coding/WM/YATwm", + "file": "/home/boss/Documents/Coding/WM/YATwm/main.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/main.o" + }, + { + "arguments": [ + "/usr/bin/g++", + "-std=c++17", + "-I/usr/include/gdk-pixbuf-2.0", + "-I/usr/include/glib-2.0", + "-I/usr/lib64/glib-2.0/include", + "-I/usr/include/sysprof-4", + "-I/usr/include/libpng16", + "-I/usr/include/libmount", + "-I/usr/include/blkid", + "-pthread", + "-c", + "-o", + "util.o", + "util.cpp" + ], + "directory": "/home/boss/Documents/Coding/WM/YATwm", + "file": "/home/boss/Documents/Coding/WM/YATwm/util.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/util.o" + }, + { + "arguments": [ + "/usr/bin/g++", + "-std=c++17", + "-I/usr/include/gdk-pixbuf-2.0", + "-I/usr/include/glib-2.0", + "-I/usr/lib64/glib-2.0/include", + "-I/usr/include/sysprof-4", + "-I/usr/include/libpng16", + "-I/usr/include/libmount", + "-I/usr/include/blkid", + "-pthread", + "-c", + "-o", + "config.o", + "config.cpp" + ], + "directory": "/home/boss/Documents/Coding/WM/YATwm", + "file": "/home/boss/Documents/Coding/WM/YATwm/config.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/config.o" + }, + { + "arguments": [ + "/usr/bin/g++", + "-std=c++17", + "-I/usr/include/gdk-pixbuf-2.0", + "-I/usr/include/glib-2.0", + "-I/usr/lib64/glib-2.0/include", + "-I/usr/include/sysprof-4", + "-I/usr/include/libpng16", + "-I/usr/include/libmount", + "-I/usr/include/blkid", + "-pthread", + "-c", + "-o", + "keybinds.o", + "keybinds.cpp" + ], + "directory": "/home/boss/Documents/Coding/WM/YATwm", + "file": "/home/boss/Documents/Coding/WM/YATwm/keybinds.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/keybinds.o" + }, + { + "arguments": [ + "/usr/bin/g++", + "-std=c++17", + "-I/usr/include/gdk-pixbuf-2.0", + "-I/usr/include/glib-2.0", + "-I/usr/lib64/glib-2.0/include", + "-I/usr/include/sysprof-4", + "-I/usr/include/libpng16", + "-I/usr/include/libmount", + "-I/usr/include/blkid", + "-pthread", + "-c", + "-o", + "commands.o", + "commands.cpp" + ], + "directory": "/home/boss/Documents/Coding/WM/YATwm", + "file": "/home/boss/Documents/Coding/WM/YATwm/commands.cpp", + "output": "/home/boss/Documents/Coding/WM/YATwm/commands.o" + } +] diff --git a/src/IPC.cpp b/src/IPC.cpp new file mode 100644 index 0000000..0aed97e --- /dev/null +++ b/src/IPC.cpp @@ -0,0 +1,86 @@ +#include "IPC.h" +#include "ewmh.h" + +#include +#include +#include +#include +#include + +using std::cout, std::endl; + +static const char* path = "/tmp/YATwm.sock"; + +IPCModule::IPCModule(CommandsModule& commandsModule, Config& cfg, Globals& globals) + :commandsModule(commandsModule), + cfg(cfg), + globals(globals) +{ + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + address.sun_family = AF_UNIX; + strcpy(address.sun_path, path); + unlink(address.sun_path); + len = strlen(address.sun_path) + sizeof(address.sun_family); + + if(bind(sockfd, (sockaddr*)&address, len) == -1) + { + cout << "ERROR " << errno << endl; + } + cout << "SOCKETED" << endl; +} + +void IPCModule::init() +{ + setIPCPath((unsigned char*)path, strlen(path)); +} + +void IPCModule::doListen() +{ + if(listen(sockfd, 1) != 0) + { + cout << "ERROR 2" << endl; + return; + } + if(first) + { + first = false; + return; + } + cout << "DOLISTEN" << endl; + unsigned int socklen = 0; + sockaddr_un remote; + int newsock = accept(sockfd, (sockaddr*)&remote, &socklen); + cout << "LISTENING" << endl; + char buffer[256]; + memset(buffer, 0, 256); + read(newsock, buffer, 256); + std::string command(buffer); + while(command[command.size() - 1] == 0 || command[command.size() - 1] == '\n') + command = command.substr(0, command.size() - 1); + //cout << '"' << command << '"' << endl; + try + { + commandsModule.runCommand(command); + } + catch(Err e) + { + cout << e.code << " " << e.message << endl; + } + char* message = "RAN COMMAND"; + send(newsock, message, strlen(message), 0); + cout << "RAN COMMAND" << endl; + shutdown(newsock, SHUT_RDWR); + close(newsock); +} + +void IPCModule::quitIPC() +{ + close(sockfd); +} + +int IPCModule::getFD() +{ + if(sockfd > 0) + return sockfd; + return -1; +} diff --git a/src/IPC.h b/src/IPC.h new file mode 100644 index 0000000..89e67e5 --- /dev/null +++ b/src/IPC.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#include "commands.h" +#include "config.h" +#include "util.h" + +class IPCModule +{ +public: + IPCModule(CommandsModule& commandsModule, Config& cfg, Globals& globals); + void init(); + void doListen(); + void quitIPC(); + int getFD(); +private: + CommandsModule& commandsModule; + Config& cfg; + Globals& globals; + int sockfd; + int len; + bool first = true; + sockaddr_un address; +}; diff --git a/src/commands.cpp b/src/commands.cpp new file mode 100644 index 0000000..57cfd0b --- /dev/null +++ b/src/commands.cpp @@ -0,0 +1,335 @@ +#include "commands.h" +#include "error.h" +#include "util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::cout, std::endl, std::string, std::vector; + +const void CommandsModule::echo(const CommandArg* argv) +{ + cout << argv[0].str << endl; +} + +CommandsModule::CommandsModule() +{ + addCommand("echo", &CommandsModule::echo, 1, {STR_REST}, this); +} +CommandsModule::~CommandsModule() +{ + for(Command c : commandList) + { + if(c.argc > 0) + delete[] c.argTypes; + } +} + +void CommandsModule::addCommand(Command c) +{ + if(lookupCommand(c.name) != nullptr) + { + cout << "Duplicate command: " << c.name << endl; + } + commandList.push_back(c); +} +void CommandsModule::addCommand(std::string name, const void (*func)(const CommandArg *), const int argc, CommandArgType *argTypes) +{ + Command c = {name, nullptr, func, argc, argTypes, nullptr}; + addCommand(c); +} +void CommandsModule::addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, std::vector argTypes) +{ + CommandArgType* argTypesArr = new CommandArgType[argc]; + for(int i = 0; i < argc; i++) + { + argTypesArr[i] = argTypes[i]; + } + addCommand(name, func, argc, argTypesArr); +} + +struct NameMatches +{ + NameMatches(string s): s_{s} {} + bool operator()(Command c) { return (c.name == s_); } + string s_; +}; + +Command* CommandsModule::lookupCommand(string name) +{ + auto elem = std::find_if(commandList.begin(), commandList.end(), NameMatches(name)); + if (elem != commandList.end()) + { + int i = elem - commandList.begin(); + return &(commandList[i]); + } + else + { + return nullptr; + } +} + +vector CommandsModule::splitCommand(string command) +{ + vector v; + string arg = ""; + bool inQuotes = false; + bool escapeNext = true; + char quoteType; + for(int i = 0; i < command.size(); i++) + { + if(escapeNext) + { + arg += command[i]; + escapeNext = false; + } + else if(command[i] == '\\') + { + escapeNext = true; + } + else if(inQuotes) + { + if(command[i] == quoteType) + { + if(arg != "") + { + v.push_back(arg); + arg = ""; + } + inQuotes = false; + } + else + { + arg += command[i]; + } + } + else + { + if(command[i] == ' ') + { + if(arg != "") + { + v.push_back(arg); + arg = ""; + } + } + else if(command[i] == '"' || command[i] == '\'') + { + inQuotes = true; + quoteType = command[i]; + } + else + { + arg += command[i]; + } + } + } + if(arg != "") + v.push_back(arg); + return v; +} + +CommandArg* CommandsModule::getCommandArgs(vector& split, const CommandArgType* argTypes, const int argc) +{ + CommandArg* args = new CommandArg[argc]; + for(int i = 1; i < argc + 1; i++) + { + switch(argTypes[i-1]) + { + case STR: args[i-1].str = (char*)split[i].c_str(); break; + case NUM: + { + try + { + args[i-1].num = std::stoi(split[i]); + break; + } + catch(std::invalid_argument e) + { + delete[] args; + throw Err(CMD_ERR_WRONG_ARGS, split[i] + " is not a number!"); + } + } + case MOVDIR: + { + if(lowercase(split[i]) == "up") + args[i-1].dir = UP; + else if(lowercase(split[i]) == "down") + args[i-1].dir = DOWN; + else if(lowercase(split[i]) == "left") + args[i-1].dir = LEFT; + else if(lowercase(split[i]) == "right") + args[i-1].dir = RIGHT; + else + { + delete[] args; + throw Err(CMD_ERR_WRONG_ARGS, split[i] + " is not a direction!"); + } + break; + } + case STR_REST: + { + string rest = ""; + for(int j = i; j < split.size(); j++) + { + rest += split[j]; + if(j != split.size() - 1) + rest += " "; + } + args[i-1].str = new char[rest.size()]; + strcpy(args[i-1].str, rest.c_str()); + return args; + } + case NUM_ARR_REST: + { + int* rest = new int[split.size() - i]; + for(int j = 0; j < split.size() - i; j++) + { + try + { + rest[j] = std::stoi(split[j + i]); + } + catch(std::invalid_argument e) + { + delete[] rest; + delete[] args; + throw Err(CMD_ERR_WRONG_ARGS, split[i] + " is not a number!"); + } + } + args[i-1].numArr = {rest, (int) split.size() - i}; + return args; + } + default: cout << "UH OH SOMETHING IS VERY WRONG" << endl; + } + } + return args; +} + +void CommandsModule::runCommand(string command) +{ + vector split = splitCommand(command); + vector::const_iterator start = split.begin(); + int count = 0; + for(string s : split) + { + if(s == ";") + { + vector::const_iterator end = start + count; + vector partialCmd(start, end); + runCommand(partialCmd); + count = 0; + start = end + 1; + } + else + { + count++; + } + } + if(start != split.end()) + { + vector partialCmd(start, (vector::const_iterator)split.end()); + runCommand(partialCmd); + } +} +void CommandsModule::runCommand(vector split) +{ + Command* cmd = lookupCommand(split[0]); + if(cmd == nullptr) + throw Err(CMD_ERR_NOT_FOUND, split[0] + " is not a valid command name"); + if(cmd->argc > split.size() - 1) + throw Err(CMD_ERR_WRONG_ARGS, "wrong number of arguments"); + CommandArg* args; + try + { + args = getCommandArgs(split, cmd->argTypes, cmd->argc); + } + catch(Err e) + { + throw e; + } + try + { + if(cmd->module == nullptr) + cmd->staticFunc(args); + else + cmd->func(*cmd->module, args); + } + catch (Err e) + { + for(int i = 0; i < cmd->argc; i++) + { + if(cmd->argTypes[i] == STR_REST) + delete[] args[i].str; + } + delete[] args; + throw e; + } + for(int i = 0; i < cmd->argc; i++) + { + if(cmd->argTypes[i] == STR_REST) + delete[] args[i].str; + } + delete[] args; +} + +vector CommandsModule::checkCommand(string command) +{ + vector errs; + vector split = splitCommand(command); + vector::const_iterator start = split.begin(); + int count = 0; + for(string s : split) + { + if(s == ";") + { + vector::const_iterator end = start + count; + vector partialCmd(start, end); + errs.push_back(checkCommand(partialCmd)); + count = 0; + start = end + 1; + } + else + { + count++; + } + } + if(start != split.end()) + { + vector partialCmd(start, (vector::const_iterator)split.end()); + errs.push_back(checkCommand(partialCmd)); + } + return errs; +} + +Err CommandsModule::checkCommand(vector split) +{ + Command* cmd = lookupCommand(split[0]); + if(cmd == nullptr) + return Err(CMD_ERR_NOT_FOUND, split[0] + " is not a valid command name"); + if(cmd->argc > split.size()) + return Err(CMD_ERR_WRONG_ARGS, "wrong number of arguments"); + CommandArg* args; + try + { + args = getCommandArgs(split, cmd->argTypes, cmd->argc); + } + catch(Err e) + { + return e; + } + for(int i = 0; i < cmd->argc; i++) + { + if(cmd->argTypes[i] == STR_REST || cmd->argTypes[i] == NUM_ARR_REST) + delete[] args[i].str; + } + delete[] args; + return Err(NOERR, ""); +} diff --git a/src/commands.h b/src/commands.h new file mode 100644 index 0000000..af4a4a0 --- /dev/null +++ b/src/commands.h @@ -0,0 +1,89 @@ +#pragma once + +#include "error.h" + +#include +#include +#include +#include + +enum MoveDir + { + UP, + RIGHT, + DOWN, + LEFT + }; +enum CommandArgType + { + STR, + NUM, + MOVDIR, + STR_REST, + NUM_ARR_REST + }; + +struct NumArr +{ + int* arr; + int size; +}; +typedef union +{ + char* str; + int num; + NumArr numArr; + MoveDir dir; +} CommandArg; + +struct Command +{ + const std::string name; + const std::function func; + const std::function staticFunc; + const int argc; + CommandArgType* argTypes; + std::any* module; +}; +class CommandsModule +{ +private: + std::vector commandList; + std::vector splitCommand(std::string command); + CommandArg* getCommandArgs(std::vector& args, const CommandArgType* argTypes, const int argc); + const void echo(const CommandArg* argv); +public: + CommandsModule(); + ~CommandsModule(); + template + void addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, CommandArgType* argTypes, T* module); + void addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, CommandArgType* argTypes); + template + void addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, std::vector argTypes, T* module); + void addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, std::vector argTypes); + void addCommand(Command c); + Command* lookupCommand(std::string name); + void runCommand(std::string command); + void runCommand(std::vector split); + std::vector checkCommand(std::string command); + Err checkCommand(std::vector split); +}; + +// YES I KNOW THIS IS BAD +// but it needs to be done this way +template +void CommandsModule::addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, CommandArgType* argTypes, T* module) +{ + Command c = {name, (const void*(std::any::*)(const CommandArg* argv)) func, nullptr, argc, argTypes, (std::any*)module}; + addCommand(c); +} +template +void CommandsModule::addCommand(std::string name, const void(T::*func)(const CommandArg*), const int argc, std::vector argTypes, T* module) +{ + CommandArgType* argTypesArr = new CommandArgType[argc]; + for(int i = 0; i < argc; i++) + { + argTypesArr[i] = argTypes[i]; + } + addCommand(name, func, argc, argTypesArr, module); +} diff --git a/src/config.cpp b/src/config.cpp new file mode 100644 index 0000000..3af2491 --- /dev/null +++ b/src/config.cpp @@ -0,0 +1,132 @@ +#include "config.h" +#include "commands.h" +#include "error.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//Just for testing +#include + +using std::string; + +// For testing +using std::cout, std::endl; + +const void Config::gapsCmd(const CommandArg* argv) +{ + gaps = argv[0].num; +} + +const void Config::outerGapsCmd(const CommandArg* argv) +{ + outerGaps = argv[0].num; +} + +const void Config::logFileCmd(const CommandArg* argv) +{ + logFile = argv[0].str; +} + +const void Config::addWorkspaceCmd(const CommandArg* argv) +{ + int* prefs = new int[argv[1].numArr.size]; + for(int i = 0; i < argv[1].numArr.size; i++) + { + prefs[i] = argv[1].numArr.arr[i] - 1; + } + workspaces.push_back({argv[0].str, prefs, argv[1].numArr.size}); + numWS++; +} + +const void Config::swapSuperAltCmd(const CommandArg* argv) +{ + swapSuperAlt ^= true; +} + +Config::Config(CommandsModule& commandsModule) + : commandsModule(commandsModule) +{ + //Register commands for config + commandsModule.addCommand("gaps", &Config::gapsCmd, 1, {NUM}, this); + commandsModule.addCommand("outergaps", &Config::outerGapsCmd, 1, {NUM}, this); + commandsModule.addCommand("logfile", &Config::logFileCmd, 1, {STR_REST}, this); + commandsModule.addCommand("addworkspace", &Config::addWorkspaceCmd, 2, {STR, NUM_ARR_REST}, this); + commandsModule.addCommand("swapmods", &Config::swapSuperAltCmd, 0, {}, this); +} + +std::vector Config::reloadFile() +{ + if(!loaded) + return {{CFG_ERR_NON_FATAL, "Not loaded config yet"}}; + return loadFromFile(file); +} + +std::vector Config::loadFromFile(std::string path) +{ + std::vector errs; + + file = path; + + std::ifstream config(path); + if(!config.good()) + { + config = std::ifstream("/etc/YATwm/config"); + errs.push_back({CFG_ERR_FATAL, "Using default config: /etc/YATwm/config"}); + } + + //Set defaults + gaps = 10; + outerGaps = 10; + logFile = "/tmp/yatlog.txt"; + numWS = 0; + swapSuperAlt = false; + workspaces = std::vector(); + + //Probably need something for workspaces and binds too... + + string cmd; + int line = 0; + while(getline(config, cmd)) + { + line++; + if(cmd.size() == 0) + continue; + if(cmd.at(0) == '#') + continue; + try + { + commandsModule.runCommand(cmd); + } + catch (Err e) + { + errs.push_back({e.code, "Error in config (line " + std::to_string(line) + "): " + std::to_string(e.code) + "\n\tMessage: " + e.message}); + + } + } + loaded = true; + return errs; +} + +Config::~Config() +{ + free(); +} +void Config::free() +{ + if(!loaded) + return; + for(Workspace w : workspaces) + { + delete [] w.screenPreferences; + } +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..452db9c --- /dev/null +++ b/src/config.h @@ -0,0 +1,53 @@ +#pragma once + +#include "commands.h" +#include +#include + +#include +#include + +struct Workspace +{ + std::string name; + int* screenPreferences; + int screenPreferencesc; +}; + +#define COMMAND(X) \ + const void X (const CommandArg* argv) + +class Config +{ +public: + Config(CommandsModule& commandsModule); + ~Config(); + void free(); + + std::vector loadFromFile(std::string path); + std::vector reloadFile(); + + // Main + int gaps; + int outerGaps; + std::string logFile; + + // Workspaces + std::vector workspaces; + int numWS; + bool loaded = false; + + // Binds + bool swapSuperAlt; + + // Config Commands + COMMAND(gapsCmd); + COMMAND(outerGapsCmd); + COMMAND(logFileCmd); + COMMAND(addWorkspaceCmd); + COMMAND(swapSuperAltCmd); + +private: + CommandsModule& commandsModule; + std::string file; +}; diff --git a/src/error.h b/src/error.h new file mode 100644 index 0000000..f0a67a5 --- /dev/null +++ b/src/error.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +typedef unsigned int ErrCode; + +#define NOERR 0 +#define ERR_NON_FATAL 110 +#define ERR_FATAL 120 +#define CFG_ERR_NON_FATAL 210 +#define CFG_ERR_KEYBIND 211 +#define CFG_ERR_FATAL 220 +#define CMD_ERR_NON_FATAL 310 +#define CMD_ERR_NOT_FOUND 311 +#define CMD_ERR_WRONG_ARGS 312 +#define CMD_ERR_FATAL 320 +struct Err +{ + ErrCode code; + std::string message; + Err(ErrCode code, std::string message) + { + this->code = code; + this->message = message; + } +}; diff --git a/src/ewmh.cpp b/src/ewmh.cpp new file mode 100644 index 0000000..a3cc505 --- /dev/null +++ b/src/ewmh.cpp @@ -0,0 +1,101 @@ +#include "ewmh.h" +#include +#include +#include +#include +#include +#include + +Display** dpy_; +Window* root_; + +void initEWMH(Display** dpy, Window* root, int numWS, std::vector workspaces) +{ + dpy_ = dpy; + root_ = root; + + Atom supported[] = {XInternAtom(*dpy_, "_NET_NUMBER_OF_DESKTOPS", false), XInternAtom(*dpy_, "_NET_DESKTOP_NAMES", false), XInternAtom(*dpy_, "_NET_CLIENT_LIST", false), XInternAtom(*dpy_, "_NET_CURRENT_DESKTOP", false)}; + int wsNamesLen = numWS; //For null bytes + for(int i = 0; i < numWS; i++) + { + wsNamesLen += workspaces[i].name.length(); + } + char wsNames[wsNamesLen]; + int pos = 0; + for(int i = 0; i < numWS; i++) + { + for(char toAdd : workspaces[i].name) + { + wsNames[pos++] = toAdd; + } + wsNames[pos++] = '\0'; + } + unsigned long numDesktops = numWS; + Atom netSupportedAtom = XInternAtom(*dpy_, "_NET_SUPPORTED", false); + Atom netNumDesktopsAtom = XInternAtom(*dpy_, "_NET_NUMBER_OF_DESKTOPS", false); + Atom netDesktopNamesAtom = XInternAtom(*dpy_, "_NET_DESKTOP_NAMES", false); + Atom XA_UTF8STRING = XInternAtom(*dpy_, "UTF8_STRING", false); + XChangeProperty(*dpy_, *root_, netSupportedAtom, XA_ATOM, 32, PropModeReplace, (unsigned char*)supported, 3); + XChangeProperty(*dpy_, *root_, netDesktopNamesAtom, XA_UTF8STRING, 8, PropModeReplace, (unsigned char*)&wsNames, wsNamesLen); + XChangeProperty(*dpy_, *root_, netNumDesktopsAtom, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&numDesktops, 1); + + +} + +void updateClientList(std::map clients) +{ + Atom netClientList = XInternAtom(*dpy_, "_NET_CLIENT_LIST", false); + XDeleteProperty(*dpy_, *root_, netClientList); + + std::map::iterator cItr; + for(cItr = clients.begin(); cItr != clients.end(); cItr++) + { + XChangeProperty(*dpy_, *root_, netClientList, XA_WINDOW, 32, PropModeAppend, (unsigned char*)&cItr->second.w, 1); + } + +} + +void setWindowDesktop(Window w, int desktop) +{ + unsigned long currDesktop = desktop - 1; + Atom netWMDesktop = XInternAtom(*dpy_, "_NET_WM_DESKTOP", false); + XChangeProperty(*dpy_, w, netWMDesktop, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&currDesktop, 1); +} + +void setCurrentDesktop(int desktop) +{ + unsigned long currDesktop = desktop - 1; + Atom netCurrentDesktop = XInternAtom(*dpy_, "_NET_CURRENT_DESKTOP", false); + XChangeProperty(*dpy_, *root_, netCurrentDesktop, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&currDesktop, 1); +} + +void setFullscreen(Window w, bool fullscreen) +{ + Atom netWMState = XInternAtom(*dpy_, "_NET_WM_STATE", false); + Atom netWMStateVal; + if(fullscreen) + netWMStateVal = XInternAtom(*dpy_, "_NET_WM_STATE_FULLSCREEN", false); + else + netWMStateVal = XInternAtom(*dpy_, "", false); + XChangeProperty(*dpy_, w, netWMState, XA_ATOM, 32, PropModeReplace, (unsigned char*)&netWMStateVal, 1); + +} + +void setIPCPath(unsigned char* path, int len) +{ + Atom socketPathAtom = XInternAtom(*dpy_, "YATWM_SOCKET_PATH", false); + XChangeProperty(*dpy_, *root_, socketPathAtom, XA_STRING, 8, PropModeReplace, path, len); +} + +int getProp(Window w, char* propName, Atom* type, unsigned char** data) +{ + Atom prop_type = XInternAtom(*dpy_, propName, false); + int format; + unsigned long length; + unsigned long after; + int status = XGetWindowProperty(*dpy_, w, prop_type, + 0L, 1L, False, + AnyPropertyType, type, &format, + &length, &after, data); + return(status); +} diff --git a/src/ewmh.h b/src/ewmh.h new file mode 100644 index 0000000..9473d5d --- /dev/null +++ b/src/ewmh.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include "structs.h" +#include "config.h" + +void initEWMH(Display** dpy, Window* root, int numWS, std::vector workspaces); + +void updateClientList(std::map clients); + +void setWindowDesktop(Window w, int desktop); + +void setCurrentDesktop(int desktop); + +void setFullscreen(Window w, bool fullscreen); + +void setIPCPath(unsigned char* path, int len); + +int getProp(Window w, char* propName, Atom* type, unsigned char** data); diff --git a/src/keybinds.cpp b/src/keybinds.cpp new file mode 100644 index 0000000..c41452f --- /dev/null +++ b/src/keybinds.cpp @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "commands.h" +#include "error.h" +#include "keybinds.h" +#include "util.h" + +using std::string; + +bool Keybind::operator<(const Keybind &o) const { + if(key != o.key) + { + return key < o.key; + } + else return modifiers < o.modifiers; +} +bool Keybind::operator==(const Keybind &o) const { + return (key == o.key && modifiers == o.modifiers); +} + +KeybindsModule::KeybindsModule(CommandsModule& commandsModule, Config& cfg, Globals& globals, void (*updateMousePos)()) + :commandsModule(commandsModule), + globals(globals), + cfg(cfg) +{ + commandsModule.addCommand("bind", &KeybindsModule::bind, 2, {STR, STR_REST}, this); + commandsModule.addCommand("quitkey", &KeybindsModule::quitKey, 1, {STR}, this); + commandsModule.addCommand("bindmode", &KeybindsModule::bindMode, 1, {STR}, this); + + bindModes = { + {"normal", &KeybindsModule::normalBindMode}, + {"emacs", &KeybindsModule::emacsBindMode} + }; + bindFunc = &KeybindsModule::normalBindMode; + + this->updateMousePos = updateMousePos; + keyMaps.insert({0, std::map()}); +} + +void KeybindsModule::changeMap(int newMapID) +{ + if(currentMapID == newMapID) + return; + if(currentMapID != 0) + XUngrabKeyboard(globals.dpy, CurrentTime); + XUngrabButton(globals.dpy, AnyKey, AnyModifier, globals.root); + currentMapID = newMapID; + if(newMapID == 0) + { + for(std::pair pair : getKeymap(currentMapID)) + { + Keybind bind = pair.first; + XGrabKey(globals.dpy, bind.key, bind.modifiers, globals.root, false, GrabModeAsync, GrabModeAsync); + } + } + else + { + XGrabKeyboard(globals.dpy, globals.root, false, GrabModeAsync, GrabModeAsync, CurrentTime); + } +} + +const void KeybindsModule::handleKeypress(XKeyEvent e) +{ + if(e.same_screen!=1) return; + // cout << "Key Pressed" << endl; + // cout << "\tState: " << e.state << endl; + // cout << "\tCode: " << XKeysymToString(XKeycodeToKeysym(globals.dpy, e.keycode, 0)) << endl; + updateMousePos(); + + const unsigned int masks = ShiftMask | ControlMask | Mod1Mask | Mod4Mask; + Keybind k = {(KeyCode)e.keycode, e.state & masks}; + if(k == exitBind) + { + changeMap(0); + } + else if(getKeymap(currentMapID).count(k) > 0) + { + KeyFunction& c = getKeymap(currentMapID).find(k)->second; + if(getKeymap(c.mapID).size() == 0) + { + commandsModule.runCommand(c.command); + changeMap(0); + } + else + { + XUngrabButton(globals.dpy, AnyKey, AnyModifier, globals.root); + changeMap(c.mapID); + } + } + else if(std::find(std::begin(ignoredKeys), std::end(ignoredKeys), e.keycode) == std::end(ignoredKeys)) + { + changeMap(0); + } +} + +bool isUpper(const std::string& s) { + return std::all_of(s.begin(), s.end(), [](unsigned char c){ return std::isupper(c); }); +} + +const void KeybindsModule::bindMode(const CommandArg* argv) +{ + if(bindModes.count(argv[0].str) < 1) + { + throw Err(CFG_ERR_KEYBIND, "Bind mode: " + string(argv[0].str) + " does not exist"); + } + else + { + bindFunc = bindModes.find(argv[0].str)->second; + } +} + +Keybind KeybindsModule::getKeybind(std::string bindString) +{ + return (this->*bindFunc)(bindString); +} + +const Keybind KeybindsModule::normalBindMode(string bindString) +{ + std::vector keys = split(bindString, '+'); + Keybind bind; + bind.modifiers = 0; + for(string key : keys) + { + if(key == "mod") + { + bind.modifiers |= Mod4Mask >> 3 * cfg.swapSuperAlt; + } + else if(key == "alt") + { + bind.modifiers |= Mod1Mask << 3 * cfg.swapSuperAlt; + } + else if(key == "shift") + { + bind.modifiers |= ShiftMask; + } + else if(key == "control") + { + bind.modifiers |= ControlMask; + } + else + { + if(isUpper(key)) + { + bind.modifiers |= ShiftMask; + } + KeySym s = XStringToKeysym(key.c_str()); + if(s == NoSymbol) + { + throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!"); + } + bind.key = XKeysymToKeycode(globals.dpy, s); + } + } + if(!bind.key) + throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!"); + return bind; +} + +const Keybind KeybindsModule::emacsBindMode(string bindString) +{ + Keybind bind; + bind.modifiers = 0; + + const std::regex keyRegex("^(?:([CMs])-)?(?:([CMs])-)?(?:([CMs])-)?([^\\s]|(SPC|ESC|RET|))$"); + std::smatch keyMatch; + if(std::regex_match(bindString, keyMatch, keyRegex)) + { + for (int i = 1; i < 3; i++) + { + std::ssub_match modifierMatch = keyMatch[i]; + if(modifierMatch.matched) + { + std::string modifier = modifierMatch.str(); + if(modifier == "s") + { + bind.modifiers |= Mod4Mask >> 3 * cfg.swapSuperAlt; + } + else if(modifier == "M") + { + bind.modifiers |= Mod1Mask << 3 * cfg.swapSuperAlt; + } + else if(modifier == "C") + { + bind.modifiers |= ControlMask; + } + } + } + } + KeySym keySym = XStringToKeysym(keyMatch[4].str().c_str()); + + if(isUpper(keyMatch[4].str().c_str()) && keySym != NoSymbol) + { + bind.modifiers |= ShiftMask; + } + if(keySym == NoSymbol) + { + if(keyMatch[4].str() == "RET") + keySym = XK_Return; + else if(keyMatch[4].str() == "ESC") + keySym = XK_Escape; + else if(keyMatch[4].str() == "SPC") + keySym = XK_space; + else if(keyMatch[4].str() == "-") + keySym = XK_minus; + else if(keyMatch[4].str() == "+") + keySym = XK_plus; + else + throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid"); + } + bind.key = XKeysymToKeycode(globals.dpy, keySym); + + return bind; +} + +const void KeybindsModule::bind(const CommandArg* argv) +{ + std::vector errs = commandsModule.checkCommand(argv[1].str); + for(Err e : errs) + { + if(e.code != NOERR) + { + e.message = "Binding fail - " + e.message; + throw e; + } + } + std::vector keys = split(argv[0].str, ' '); + int currentBindingMap = 0; + for(int i = 0; i < keys.size() - 1; i++) + { + Keybind bind = getKeybind(keys[i]); + if(getKeymap(currentBindingMap).count(bind) > 0) + { + currentBindingMap = getKeymap(currentBindingMap).find(bind)->second.mapID; + } + else + { + KeyFunction newMap = {"", nextKeymapID}; + keyMaps.insert({nextKeymapID, std::map()}); + nextKeymapID++; + getKeymap(currentBindingMap).insert({bind, newMap}); + currentBindingMap = getKeymap(currentBindingMap).find(bind)->second.mapID; + } + } + Keybind bind = getKeybind(keys[keys.size() - 1]); + if(getKeymap(currentBindingMap).count(bind) <= 0) + { + KeyFunction function = {argv[1].str, nextKeymapID}; + keyMaps.insert({nextKeymapID, std::map()}); + nextKeymapID++; + getKeymap(currentBindingMap).insert({bind, function}); + if(currentBindingMap == currentMapID) + { + KeyCode c = XKeysymToKeycode(globals.dpy, bind.key); + XGrabKey(globals.dpy, c, bind.modifiers, globals.root, false, GrabModeAsync, GrabModeAsync); + } + } + else + { + throw Err(CFG_ERR_KEYBIND, "Bind is a keymap already!"); + } + // cout << "Added bind" << endl; + // cout << "\t" << argv[0].str << endl; +} + +const void KeybindsModule::quitKey(const CommandArg* argv) +{ + exitBind = getKeybind(argv[0].str); +} + +const void KeybindsModule::clearKeybinds() +{ + XUngrabButton(globals.dpy, AnyKey, AnyModifier, globals.root); + keyMaps = std::map>(); + keyMaps.insert({0, std::map()}); +} diff --git a/src/keybinds.h b/src/keybinds.h new file mode 100644 index 0000000..a742240 --- /dev/null +++ b/src/keybinds.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include "commands.h" +#include "config.h" +#include "util.h" + +struct Keybind { + KeyCode key; + unsigned int modifiers; + bool operator<(const Keybind &o) const; + bool operator==(const Keybind &o) const; +}; + +struct KeyFunction +{ + std::string command; + int mapID; +}; + +#define getKeymap(X) \ + keyMaps.find(X)->second + + +class KeybindsModule +{ +public: + KeybindsModule(CommandsModule& commandsModule, Config& cfg, Globals& globals, void (*updateMousePos)()); + ~KeybindsModule() = default; + const void bind(const CommandArg* argv); + const void quitKey(const CommandArg* argv); + const void bindMode(const CommandArg* argv); + const void handleKeypress(XKeyEvent e); + const void clearKeybinds(); +private: + Keybind getKeybind(std::string bindString); + void changeMap(int newMapID); + std::map> keyMaps; + const Keybind emacsBindMode(std::string bindString); + const Keybind normalBindMode(std::string bindString); + std::map bindModes; + const Keybind(KeybindsModule::* bindFunc)(std::string bindString); + // Modifier keys to ignore when canceling a keymap + KeyCode ignoredKeys[8] = {50, 37, 133, 64, 62, 105, 134, 108}; + int currentMapID = 0; + int nextKeymapID = 1; + Keybind exitBind = {42, 0x40}; + CommandsModule& commandsModule; + Config& cfg; + Globals& globals; + void (*updateMousePos)(); +}; diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..1f3edc2 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,1159 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "IPC.h" +#include "commands.h" +#include "keybinds.h" +#include "structs.h" +#include "config.h" +#include "util.h" +#include "ewmh.h" +#include "error.h" + +using std::cout; +using std::string; +using std::endl; +using std::map; +using std::pair; +using std::vector; + +std::ofstream yatlog; +std::time_t timeNow; +std::tm *now; +char nowString[80]; + +#define log(x) \ + updateTime(); \ + yatlog << nowString << x << std::endl + +Display* dpy; +Window root; + +Globals globals = {dpy, root}; + +void updateMousePos(); + +CommandsModule commandsModule; +Config cfg(commandsModule); +KeybindsModule keybindsModule(commandsModule, cfg, globals, &updateMousePos); +IPCModule ipc(commandsModule, cfg, globals); + +int sW, sH; +int bH; +TileDir nextDir = horizontal; + +bool keepGoing = true; + +map clients; +int currClientID = 0; +map frames; +int currFrameID = 1; +map frameIDS; + +ScreenInfo* screens; +int* focusedWorkspaces; +int focusedScreen = 0; +int nscreens; +int mX, mY; + +#define getClient(c) clients.find(c)->second +#define getFrame(f) frames.find(f)->second +#define getFrameID(w) frameIDS.find(w)->second + +Window bar; + +int currWS = 1; + + +// Usefull functions +int FFCF(int sID); +void detectScreens(); +void focusRoot(int root); +void handleConfigErrs(vector cfgErrs); +void updateTime(); + +void configureRequest(XConfigureRequestEvent e); +void mapRequest(XMapRequestEvent e); +void destroyNotify(XDestroyWindowEvent e); +void enterNotify(XEnterWindowEvent e); +void clientMessage(XClientMessageEvent e); + +static int OnXError(Display* display, XErrorEvent* e); + +// Tiling +// Call this one to tile everything (it does all the fancy stuff trust me just call this one) +void tileRoots(); +// Call this one to until everything (it handles multiple monitors) +void untileRoots(); +// This is to be called by tileRoots, it takes in the x, y, w, and h of where it's allowed to tile windows to, and returns the ID of a fullscreen client if one is found, or noID (-1) if none are found +int tile(int frameID, int x, int y, int w, int h); +// This is to be called by tileRoots, it takes in a frameID and recursively unmaps all its children +void untile(int frameID); + +// Usefull functions +int FFCF(int sID) +{ + if(frames.find(sID)->second.isClient) + return sID; + return FFCF(frames.find(sID)->second.subFrameIDs[0]); +} +void detectScreens() +{ + delete[] screens; + delete[] focusedWorkspaces; + log("Detecting screens: "); + XRRMonitorInfo* monitors = XRRGetMonitors(dpy, root, true, &nscreens); + log("\t" << nscreens << " monitors"); + screens = new ScreenInfo[nscreens]; + focusedWorkspaces = new int[nscreens]; + for(int i = 0; i < nscreens; i++) + { + focusedWorkspaces[i] = i * 5 + 1; + char* name = XGetAtomName(dpy, monitors[i].name); + screens[i] = {name, monitors[i].x, monitors[i].y, monitors[i].width, monitors[i].height}; + log("\tMonitor " << i + 1 << " - " << screens[i].name); + log("\t\tx: " << screens[i].x << ", y: " << screens[i].y); + log("\t\tw: " << screens[i].w << ", h: " << screens[i].h); + XFree(name); + } + for(int i = 0; i < cfg.workspaces.size(); i++) + { + if(cfg.workspaces[i].screenPreferences[0] < nscreens && focusedWorkspaces[cfg.workspaces[i].screenPreferences[0]] == 0) + { + //focusedWorkspaces[screenPreferences[i][0]] = i+1; + } + } + XFree(monitors); +} +void updateMousePos() +{ + Window rootRet, childRet; + int rX, rY, cX, cY; + unsigned int maskRet; + XQueryPointer(dpy, root, &rootRet, &childRet, &rX, &rY, &cX, &cY, &maskRet); + mX = rX; + mY = rY; +} +int getClientChild(int fID) +{ + if(getFrame(fID).isClient) + return fID; + else + return getClientChild(getFrame(fID).subFrameIDs[0]); +} +void focusRoot(int root) +{ + //log("Focusing root: " << root); + if(getFrame(root).subFrameIDs.size() == 0) + { + //log("\tRoot has no children"); + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + return; + } + int client = getFrame(getClientChild(root)).cID; + Window w = getClient(client).w; + //log("\tFocusing window: " << w); + XSetInputFocus(dpy, w, RevertToPointerRoot, CurrentTime); +} +void handleConfigErrs(vector cfgErrs) +{ + for(Err cfgErr : cfgErrs) + { + if(cfgErr.code == CFG_ERR_FATAL) + { + log("YATwm fatal error (Code " << cfgErr.code << ")\n" << cfgErr.message); + std::string title = "YATwm fatal config error (Code " + std::to_string(cfgErr.code) + ")"; + std::string body = cfgErr.message; + NotifyNotification* n = notify_notification_new(title.c_str(), + body.c_str(), + 0); + notify_notification_set_timeout(n, 10000); + if(!notify_notification_show(n, 0)) + { + log("notification failed"); + } + } + else + { + log("YATwm non fatal error (Code " << cfgErr.code << ")\n" << cfgErr.message); + std::string title = "YATwm non fatal config error (Code " + std::to_string(cfgErr.code) + ")"; + std::string body = "Check logs for more information"; + NotifyNotification* n = notify_notification_new(title.c_str(), + body.c_str(), + 0); + notify_notification_set_timeout(n, 10000); + if(!notify_notification_show(n, 0)) + { + log("notification failed"); + } + } + } +} +void updateTime() +{ + timeNow = std::time(0); + now = std::localtime(&timeNow); + strftime(nowString, sizeof(nowString), "[%H:%M:%S] ", now); +} + +//Keybind commands +const void exit(const CommandArg* argv) +{ + keepGoing = false; +} +const void spawn(const CommandArg* argv) +{ + if(fork() == 0) + { + const std::string argsStr = argv[0].str; + vector args = split(argsStr, ' '); + char** execvpArgs = new char*[args.size()]; + for(int i = 0; i < args.size(); i++) + { + execvpArgs[i] = strdup(args[i].c_str()); + } + int null = open("/dev/null", O_WRONLY); + dup2(null, 0); + dup2(null, 1); + dup2(null, 2); + execvp(execvpArgs[0], execvpArgs); + exit(0); + } +} +const void spawnOnce(const CommandArg* argv) +{ + if(cfg.loaded) + return; + else spawn(argv); +} +const void toggle(const CommandArg* argv) +{ + nextDir = nextDir = (nextDir==horizontal)? vertical : horizontal; +} +const void kill(const CommandArg* argv) +{ + Window w; + int revertToReturn; + XGetInputFocus(dpy, &w, &revertToReturn); + Atom* supported_protocols; + int num_supported_protocols; + if (XGetWMProtocols(dpy, + w, + &supported_protocols, + &num_supported_protocols) && + (std::find(supported_protocols, + supported_protocols + num_supported_protocols, + XInternAtom(dpy, "WM_DELETE_WINDOW", false)) != + supported_protocols + num_supported_protocols)) { + // 1. Construct message. + XEvent msg; + memset(&msg, 0, sizeof(msg)); + msg.xclient.type = ClientMessage; + msg.xclient.message_type = XInternAtom(dpy, "WM_PROTOCOLS", false); + msg.xclient.window = w; + msg.xclient.format = 32; + msg.xclient.data.l[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", false); + // 2. Send message to window to be closed. + cout << "Nice kill\n"; + XSendEvent(dpy, w, false, 0, &msg); + } else { + cout << "Mean kill\n"; + XKillClient(dpy, w); + } +} +// Took this out as it is used commonly +void cWS(int newWS) +{ + int prevWS = currWS; + + currWS = newWS; + if(prevWS == currWS) + return; + untileRoots(); + + //log("Changing WS with keybind"); + + for(int i = 0; i < cfg.workspaces[newWS - 1].screenPreferencesc; i++) + { + if(nscreens > cfg.workspaces[newWS - 1].screenPreferences[i]) + { + int screen = cfg.workspaces[newWS - 1].screenPreferences[i]; + //log("Found screen (screen " << screenPreferences[arg.num - 1][i] << ")"); + prevWS = focusedWorkspaces[screen]; + //log("Changed prevWS"); + focusedWorkspaces[screen] = newWS; + //log("Changed focusedWorkspaces"); + if(focusedScreen != screen) + { + focusedScreen = screen; + XWarpPointer(dpy, root, root, 0, 0, 0, 0, screens[screen].x + screens[screen].w/2, screens[screen].y + screens[screen].h/2); + } + //log("Changed focusedScreen"); + break; + } + } + + //log("Finished changes"); + + //log(prevWS); + // LOOK: what is this for????? + if(prevWS < 1 || prevWS > cfg.workspaces.size()) + { + //untile(prevWS); + } + //log("Untiled"); + //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + tileRoots(); + //log("Roots tiled"); + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + + cout << focusedWorkspaces[0] << endl; + + //EWMH + setCurrentDesktop(currWS); +} +const void changeWS(const CommandArg* argv) +{ + cWS(argv[0].num); +} +const void wToWS(const CommandArg* argv) +{ + Window focusedWindow; + int revertToReturn; + XGetInputFocus(dpy, &focusedWindow, &revertToReturn); + if(focusedWindow == root) + return; + + int fID = frameIDS.find(focusedWindow)->second; + //TODO: make floating windows move WS + if(clients.find(frames.find(fID)->second.cID)->second.floating) + return; + vector& pSF = frames.find(frames.find(fID)->second.pID)->second.subFrameIDs; + for(int i = 0; i < pSF.size(); i++) + { + if(pSF[i] == fID) + { + //Frame disolve + pSF.erase(pSF.begin() + i); + int pID = frames.find(fID)->second.pID; + if(pSF.size() < 2 && !frames.find(pID)->second.isRoot) + { + //Erase parent frame + int lastChildID = frames.find(frames.find(pID)->second.subFrameIDs[0])->second.ID; + int parentParentID = frames.find(pID)->second.pID; + vector& parentParentSubFrameIDs = frames.find(parentParentID)->second.subFrameIDs; + for(int j = 0; j < parentParentSubFrameIDs.size(); j++) + { + if(parentParentSubFrameIDs[j] == pID) + { + parentParentSubFrameIDs[j] = lastChildID; + frames.find(lastChildID)->second.pID = parentParentID; + frames.erase(pID); + break; + } + } + } + + break; + } + } + frames.find(fID)->second.pID = argv[0].num; + frames.find(argv[0].num)->second.subFrameIDs.push_back(fID); + + //EWMH + setWindowDesktop(focusedWindow, argv[0].num); + + XUnmapWindow(dpy, focusedWindow); + //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + untileRoots(); + tileRoots(); + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); +} +int dirFind(int fID, MoveDir dir) +{ + vector& pSF = frames.find(frames.find(fID)->second.pID)->second.subFrameIDs; + TileDir pDir = frames.find(frames.find(fID)->second.pID)->second.dir; + + int i = 0; + for(int f : pSF) + { + if(f == fID) + { + break; + } + i++; + } + + if(pDir == vertical) + { + switch(dir) + { + case UP: i--; break; + case DOWN: i++; break; + case LEFT: return (frames.find(fID)->second.pID > cfg.numWS)? dirFind(frames.find(fID)->second.pID, dir) : fID; + case RIGHT: return (frames.find(fID)->second.pID > cfg.numWS)? dirFind(frames.find(fID)->second.pID, dir) : fID; + } + } + else if(pDir == horizontal) + { + switch(dir) + { + case LEFT: i--; break; + case RIGHT: i++; break; + case UP: return (frames.find(fID)->second.pID > cfg.numWS)? dirFind(frames.find(fID)->second.pID, dir) : fID; + case DOWN: return (frames.find(fID)->second.pID > cfg.numWS)? dirFind(frames.find(fID)->second.pID, dir) : fID; + } + } + if(i < 0) + i = pSF.size() - 1; + if(i == pSF.size()) + i = 0; + + return pSF[i]; +} +const void focChange(const CommandArg* argv) +{ + Window focusedWindow; + int revertToReturn; + XGetInputFocus(dpy, &focusedWindow, &revertToReturn); + if(focusedWindow == root) + return; + + int fID = frameIDS.find(focusedWindow)->second; + int nID = dirFind(fID, argv[0].dir); + int fNID = FFCF(nID); + Window w = clients.find(frames.find(fNID)->second.cID)->second.w; + XSetInputFocus(dpy, w, RevertToPointerRoot, CurrentTime); +} +const void wMove(const CommandArg* argv) +{ + Window focusedWindow; + int revertToReturn; + XGetInputFocus(dpy, &focusedWindow, &revertToReturn); + if(focusedWindow == root) + return; + + int fID = frameIDS.find(focusedWindow)->second; + if(clients.find(frames.find(fID)->second.cID)->second.floating) + return; + int nID = dirFind(fID, argv[0].dir); + int fNID = FFCF(nID); + int pID = frames.find(fNID)->second.pID; + int oPID = frames.find(fID)->second.pID; + + vector& pSF = frames.find(pID)->second.subFrameIDs; + vector& oPSF = frames.find(oPID)->second.subFrameIDs; + + for(int i = 0; i < frames.find(oPID)->second.subFrameIDs.size(); i++) + { + if(oPSF[i] != fID) + continue; + + if(pID!=oPID) + { + //Frame dissolve + oPSF.erase(oPSF.begin() + i); + if(oPSF.size() < 2 && !frames.find(oPID)->second.isRoot) + { + //Erase parent frame + int lastChildID = frames.find(frames.find(oPID)->second.subFrameIDs[0])->second.ID; + int parentParentID = frames.find(oPID)->second.pID; + vector& parentParentSubFrameIDs = frames.find(parentParentID)->second.subFrameIDs; + for(int j = 0; j < parentParentSubFrameIDs.size(); j++) + { + if(parentParentSubFrameIDs[j] == oPID) + { + parentParentSubFrameIDs[j] = lastChildID; + frames.find(lastChildID)->second.pID = parentParentID; + frames.erase(oPID); + break; + } + } + } + + frames.find(fID)->second.pID = pID; + pSF.push_back(fID); + } + else + { + if(frames.find(pID)->second.dir == vertical) + { + if(argv[0].dir == LEFT || argv[0].dir == RIGHT) + return; + } + else + { + if(argv[0].dir == UP || argv[0].dir == DOWN) + return; + } + + int offset; + if(argv[0].dir == UP || argv[0].dir == LEFT) + offset = -1; + else + offset = 1; + + int swapPos = i + offset; + + if(swapPos == pSF.size()) + swapPos = 0; + else if(swapPos == -1) + swapPos = pSF.size() - 1; + + std::swap(pSF[i], pSF[swapPos]); + } + untileRoots(); + tileRoots(); + //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + XSetInputFocus(dpy, focusedWindow, RevertToPointerRoot, CurrentTime); + return; + } + XSetInputFocus(dpy, focusedWindow, RevertToPointerRoot, CurrentTime); +} +const void bashSpawn(const CommandArg* argv) +{ + if(fork() == 0) + { + int null = open("/dev/null", O_WRONLY); + dup2(null, 0); + dup2(null, 1); + dup2(null, 2); + system(argv[0].str); + exit(0); + } +} +const void bashSpawnOnce(const CommandArg* argv) +{ + if(cfg.loaded) + return; + else bashSpawn(argv); +} +const void reload(const CommandArg* argv) +{ + detectScreens(); + + //Clear keybinds + keybindsModule.clearKeybinds(); + + //Load config again + vector cfgErr = cfg.reloadFile(); + //Error check + handleConfigErrs(cfgErr); + + //Re tile + untileRoots(); + tileRoots(); +} +const void wsDump(const CommandArg* argv) +{ + log("Workspace dump:"); + for(int i = 1; i < currFrameID; i++) + { + if(getFrame(i).isClient) + { + int id = i; + while(!getFrame(id).isRoot) + { + id=getFrame(id).pID; + } + log("\tClient with ID: " << getClient(getFrame(i).cID).w << ", on worskapce " << id); + } + } +} +const void nextMonitor(const CommandArg* argv) +{ + focusedScreen++; + if(focusedScreen >= nscreens) + focusedScreen = 0; + + XWarpPointer(dpy, root, root, 0, 0, 0, 0, screens[focusedScreen].x + screens[focusedScreen].w/2, screens[focusedScreen].y + screens[focusedScreen].h/2); + focusRoot(focusedWorkspaces[focusedScreen]); +} +const void fullscreen(const CommandArg* arg) +{ + Window focusedWindow; + int focusedRevert; + XGetInputFocus(dpy, &focusedWindow, &focusedRevert); + + int fID = getFrameID(focusedWindow); + int cID = getFrame(fID).cID; + getClient(cID).fullscreen ^= true; + tileRoots(); + setFullscreen(focusedWindow, getClient(cID).fullscreen); +} + +void configureRequest(XConfigureRequestEvent e) +{ + XWindowChanges changes; + changes.x = e.x; + changes.y = e.y; + changes.width = e.width; + changes.height = e.height; + changes.border_width = e.border_width; + changes.sibling = e.above; + changes.stack_mode = e.detail; + XConfigureWindow(dpy, e.window, (unsigned int) e.value_mask, &changes); + log("Configure request: " << e.window); + //XSetInputFocus(dpy, e.window, RevertToNone, CurrentTime); + //tileRoots(); +} + +void mapRequest(XMapRequestEvent e) +{ + XMapWindow(dpy, e.window); + + XTextProperty name; + bool gotName = XGetWMName(dpy, e.window, &name); + XWindowAttributes attr; + XGetWindowAttributes(dpy, e.window, &attr); + if(gotName) + { + log("Mapping window: " << name.value); + } + else + { + log("Mapping window with unknown name (its probably mpv, mpv is annoying)"); + } + log("\tWindow ID: " << e.window); + + Window focusedWindow; + int revertToReturn; + int pID; + XGetInputFocus(dpy, &focusedWindow, &revertToReturn); + if(focusedWindow && focusedWindow != root && frameIDS.count(focusedWindow)>0) + { + //Use focused to determine parent + pID = frames.find(frameIDS.find(focusedWindow)->second)->second.pID; + } + else + { + Window rootRet, childRet; + int rX, rY, cX, cY; + unsigned int maskRet; + XQueryPointer(dpy, root, &rootRet, &childRet, &rX, &rY, &cX, &cY, &maskRet); + mX = rX; + mY = rY; + int monitor = 0; + for(int i = 0; i < nscreens; i++) + { + if(screens[i].x <= mX && mX < screens[i].x + screens[i].w) + { + if(screens[i].y <= mY && mY < screens[i].y + screens[i].h) + { + monitor = i; + } + } + } + pID = focusedWorkspaces[monitor]; + focusedScreen = monitor; + /* + if(mX == rX && mY == rY) + { + //Use focused screen + log("\tFocused screen is: " << focusedScreen); + } + else + { + //Use mouse + //TODO: Make this find the monitor + log("\tMouse is at x: " << rX << ", y: " << rY); + mX = rX; + mY = rY; + } + */ + } + + unsigned char* data; + Atom type; + int status = getProp(e.window, "_NET_WM_WINDOW_TYPE", &type, &data); + if (status == Success && type != None && ((Atom*)data)[0] == XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", false)) + { + log("\tWindow was bar"); + bH = attr.height; + bar = e.window; + XFree(data); + return; + } + XFree(data); + + + + + XSelectInput(dpy, e.window, EnterWindowMask); + + //Make client + Client c = {currClientID, e.window, false, false}; + currClientID++; + + //Add to clients map + clients.insert(pair(c.ID, c)); + + //Make frame + //pID = (frameIDS.count(focusedWindow)>0)? frames.find(frameIDS.find(focusedWindow)->second)->second.pID : currWS; + vector v; + vector floating; + Frame f = {currFrameID, pID, true, c.ID, noDir, v, false, floating}; + currFrameID++; + + + //Add ID to frameIDS map + frameIDS.insert(pair(e.window, f.ID)); + + status = getProp(e.window, "_NET_WM_STATE", &type, &data); + if(status == Success && type!=None && (((Atom*)data)[0] == XInternAtom(dpy, "_NET_WM_STATE_MODAL", false) || ((Atom*)data)[0] == XInternAtom(dpy, "_NET_WM_STATE_ABOVE", false))) + { + cout << "Floating" << endl; + clients.find(c.ID)->second.floating = true; + frames.find(pID)->second.floatingFrameIDs.push_back(f.ID); + frames.insert(pair(f.ID, f)); + setWindowDesktop(e.window, currWS); + updateClientList(clients); + XFree(data); + //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + tileRoots(); + return; + } + XFree(data); + + //Check how to add + if(nextDir == frames.find(pID)->second.dir || frameIDS.count(focusedWindow)==0) + { + //Add to focused parent + frames.find(pID)->second.subFrameIDs.push_back(f.ID); + } + else + { + //Get parent sub frames for later use + vector& pS = frames.find(pID)->second.subFrameIDs; + + //Get index of focused frame in parent sub frames + int index; + for(index = 0; index < pS.size(); index++) + { + if(pS[index] == frames.find(frameIDS.find(focusedWindow)->second)->second.ID) + break; + } + + //Make new frame + vector v; + v.push_back(frames.find(frameIDS.find(focusedWindow)->second)->second.ID); + v.push_back(f.ID); + Frame pF = {currFrameID, pID, false, noID, nextDir, v, false, floating}; + + //Update the IDS + f.pID = currFrameID; + frames.find(frames.find(frameIDS.find(focusedWindow)->second)->second.ID)->second.pID = currFrameID; + pS[index] = currFrameID; + + currFrameID++; + + //Insert the new frame into the frames map + frames.insert(pair(pF.ID, pF)); + } + + //Add to frames map + frames.insert(pair(f.ID, f)); + + setWindowDesktop(e.window, currWS); + updateClientList(clients); + + //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + XSetInputFocus(dpy, e.window, RevertToNone, CurrentTime); + tileRoots(); +} + +void destroyNotify(XDestroyWindowEvent e) +{ + if(frameIDS.count(e.window)<1) + return; + log("Destroy notif"); + log("\tWindow ID: " << e.window); + int fID = frameIDS.find(e.window)->second; + int pID = frames.find(fID)->second.pID; + vector& pS = frames.find(pID)->second.subFrameIDs; + if(clients.find(frames.find(fID)->second.cID)->second.floating) + { + pS = frames.find(pID)->second.floatingFrameIDs; + } + for(int i = 0; i < pS.size(); i++) + { + if(frames.find(pS[i])->second.ID == fID) + { + pS.erase(pS.begin() + i); + clients.erase(frames.find(fID)->second.cID); + frames.erase(fID); + frameIDS.erase(e.window); + + if(pS.size() < 2 && !frames.find(pID)->second.isRoot) + { + //Erase parent frame + int lastChildID = frames.find(frames.find(pID)->second.subFrameIDs[0])->second.ID; + int parentParentID = frames.find(pID)->second.pID; + vector& parentParentSubFrameIDs = frames.find(parentParentID)->second.subFrameIDs; + for(int j = 0; j < parentParentSubFrameIDs.size(); j++) + { + if(parentParentSubFrameIDs[j] == pID) + { + parentParentSubFrameIDs[j] = lastChildID; + frames.find(lastChildID)->second.pID = parentParentID; + frames.erase(pID); + break; + } + } + } + break; + } + } + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + tileRoots(); + + updateClientList(clients); +} +void enterNotify(XEnterWindowEvent e) +{ + //log(e.xcrossing.x); + //Cancel if crossing into root + if(e.window == root) + return; + + XWindowAttributes attr; + XGetWindowAttributes(dpy, e.window, &attr); + int monitor = 0; + for(int i = 0; i < nscreens; i++) + { + if(screens[i].x <= attr.x && attr.x < screens[i].x + screens[i].w) + { + if(screens[i].y <= attr.y && attr.y < screens[i].y + screens[i].h) + { + monitor = i; + } + } + } + focusedScreen = monitor; + XSetInputFocus(dpy, e.window, RevertToNone, CurrentTime); +} +void clientMessage(XClientMessageEvent e) +{ + char* name = XGetAtomName(dpy, e.message_type); + log("Client message: " << name); + if(e.message_type == XInternAtom(dpy, "_NET_CURRENT_DESKTOP", false)) + { + cWS(e.data.l[0] + 1); + /* + //Change desktop + int nextWS = (long)e.data.l[0] + 1; + int prevWS = currWS; + currWS = nextWS; + + if(prevWS == currWS) + return; + + untile(prevWS); + tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + + //EWMH + setCurrentDesktop(currWS); + */ + } + else if(e.message_type == XInternAtom(dpy, "_NET_WM_STATE", false)) + { + if((Atom)e.data.l[0] == 0) + log("\tremove"); + if((Atom)e.data.l[0] == 1) + log("\ttoggle"); + if((Atom)e.data.l[0] == 2) + log("\tadd"); + char* prop1 = XGetAtomName(dpy, (Atom)e.data.l[1]); + if((Atom)e.data.l[1] == XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", false)) + { + int fID = getFrameID(e.window); + int cID = getFrame(fID).cID; + getClient(cID).fullscreen = (Atom) e.data.l[0] > 0; + setFullscreen(e.window, (Atom) e.data.l[0] > 0); + tileRoots(); + } + XFree(prop1); + } + XFree(name); +} + +static int OnXError(Display* display, XErrorEvent* e) +{ + char* error = new char[50]; + XGetErrorText(dpy, e->type, error, 50); + log("XError " << error); + delete[] error; + return 0; +} + +void tileRoots() +{ + for(int i = 0; i < nscreens; i++) + { + int fullscreenClientID = tile(focusedWorkspaces[i], screens[i].x + cfg.outerGaps, screens[i].y + cfg.outerGaps, screens[i].w - cfg.outerGaps*2, screens[i].h - cfg.outerGaps*2 - bH); + if(fullscreenClientID!=noID) + { + untile(focusedWorkspaces[i]); + Client c = getClient(fullscreenClientID); + XMapWindow(dpy, c.w); + XMoveWindow(dpy, c.w, + screens[i].x, screens[i].y); + XResizeWindow(dpy, c.w, + screens[i].w, screens[i].h); + } + } +} +void untileRoots() +{ + for(int i = 0; i < nscreens; i++) + { + untile(focusedWorkspaces[i]); + } +} +int tile(int frameID, int x, int y, int w, int h) +{ + for(int fID : frames.find(frameID)->second.floatingFrameIDs) + { + Window w = clients.find(frames.find(fID)->second.cID)->second.w; + XMapWindow(dpy, w); + } + TileDir dir = frames.find(frameID)->second.dir; + int i = 0; + vector& subFrameIDs = frames.find(frameID)->second.subFrameIDs; + for(int fID : subFrameIDs) + { + Frame f = frames.find(fID)->second; + int wX = (dir==horizontal) ? x + i * (w/subFrameIDs.size()) : x; + int wY = (dir==vertical) ? y + i * (h/subFrameIDs.size()) : y; + int wW = (dir==horizontal) ? w/subFrameIDs.size() : w; + int wH = (dir==vertical) ? h/subFrameIDs.size() : h; + i++; + if(i==subFrameIDs.size()) + { + wW = (dir==horizontal) ? w - (wX - x) : w; + wH = (dir==vertical) ? h - (wY - y) : h; + } + if(!f.isClient) + { + int fullscreenClientID = tile(fID, wX, wY, wW, wH); + if(fullscreenClientID == noID) + return fullscreenClientID; + continue; + } + Client c = clients.find(f.cID)->second; + if(c.fullscreen) + return c.ID; + wX += cfg.gaps; + wY += cfg.gaps; + wW -= cfg.gaps * 2; + wH -= cfg.gaps * 2; + XMapWindow(dpy, c.w); + XMoveWindow(dpy, c.w, + wX, wY); + XResizeWindow(dpy, c.w, + wW, wH); + } + return noID; +} + +void untile(int frameID) +{ + for(int fID : frames.find(frameID)->second.floatingFrameIDs) + { + Window w = clients.find(frames.find(fID)->second.cID)->second.w; + XUnmapWindow(dpy, w); + } + vector& subFrameIDs = frames.find(frameID)->second.subFrameIDs; + TileDir dir = frames.find(frameID)->second.dir; + for(int fID : subFrameIDs) + { + Frame f = frames.find(fID)->second; + if(!f.isClient) + { + untile(fID); + continue; + } + Client c = clients.find(f.cID)->second; + XUnmapWindow(dpy, c.w); + } +} + +int main(int argc, char** argv) +{ + if(argc > 1) + { + if(strcmp(argv[1], "--version") == 0) + { + const char* version = + "YATwm for X\n" + "version 0.1.0"; + cout << version << endl; + return 0; + } + } + //Important init stuff + mX = mY = 0; + dpy = XOpenDisplay(nullptr); + root = Window(DefaultRootWindow(dpy)); + + // Adding commands + commandsModule.addCommand("exit", exit, 0, {}); + commandsModule.addCommand("spawn", spawn, 1, {STR_REST}); + commandsModule.addCommand("spawnOnce", spawnOnce, 1, {STR_REST}); + commandsModule.addCommand("toggle", toggle, 0, {}); + commandsModule.addCommand("kill", kill, 0, {}); + commandsModule.addCommand("changeWS", changeWS, 1, {NUM}); + commandsModule.addCommand("wToWS", wToWS, 1, {NUM}); + commandsModule.addCommand("focChange", focChange, 1, {MOVDIR}); + commandsModule.addCommand("bashSpawn", bashSpawn, 1, {STR_REST}); + commandsModule.addCommand("bashSpawnOnce", bashSpawnOnce, 1, {STR_REST}); + commandsModule.addCommand("reload", reload, 0, {}); + commandsModule.addCommand("wsDump", wsDump, 0, {}); + commandsModule.addCommand("nextMonitor", nextMonitor, 0, {}); + commandsModule.addCommand("fullscreen", fullscreen, 0, {}); + + //Config + std::vector cfgErr; + + char* confDir = getenv("XDG_CONFIG_HOME"); + if(confDir != NULL) + { + cfgErr = cfg.loadFromFile(string(confDir) + "/YATwm/config"); + } + else + { + string home = getenv("HOME"); + cfgErr = cfg.loadFromFile(home + "/.config/YATwm/config"); + } + + //Log + yatlog.open(cfg.logFile, std::ios_base::app); + yatlog << "\n" << endl; + + //Print starting message + log("-------- YATWM STARTING --------"); + + //Notifications + notify_init("YATwm"); + + //Error check config + handleConfigErrs(cfgErr); + + screens = new ScreenInfo[1]; + focusedWorkspaces = new int[1]; + detectScreens(); + + int screenNum = DefaultScreen(dpy); + sW = DisplayWidth(dpy, screenNum); + sH = DisplayHeight(dpy, screenNum); + + //XSetErrorHandler(OnXError); + XSelectInput(dpy, root, SubstructureRedirectMask | SubstructureNotifyMask | KeyPressMask | EnterWindowMask); + + XDefineCursor(dpy, root, XCreateFontCursor(dpy, XC_top_left_arrow)); + //EWMH + initEWMH(&dpy, &root, cfg.workspaces.size(), cfg.workspaces); + setCurrentDesktop(1); + + ipc.init(); + + for(int i = 1; i < cfg.numWS + 1; i++) + { + vector v; + Frame rootFrame = {i, noID, false, noID, horizontal, v, true}; + frames.insert(pair(i, rootFrame)); + currFrameID++; + } + + XSetInputFocus(dpy, root, RevertToNone, CurrentTime); + XWarpPointer(dpy, root, root, 0, 0, 0, 0, 960, 540); + + fd_set fdset; + int x11fd = ConnectionNumber(dpy); + FD_ZERO(&fdset); + FD_SET(x11fd, &fdset); + FD_SET(ipc.getFD(), &fdset); + + log("Begin mainloop"); + while(keepGoing) + { + FD_ZERO(&fdset); + FD_SET(x11fd, &fdset); + FD_SET(ipc.getFD(), &fdset); + int ready = select(x11fd + 1, &fdset, NULL, NULL, NULL); + if(FD_ISSET(ipc.getFD(), &fdset)) + { + ipc.doListen(); + } + if(FD_ISSET(x11fd, &fdset)) + { + XEvent e; + while(XPending(dpy)) + { + XNextEvent(dpy, &e); + + switch(e.type) + { + case KeyPress: + keybindsModule.handleKeypress(e.xkey); + break; + case ConfigureRequest: + configureRequest(e.xconfigurerequest); + break; + case MapRequest: + mapRequest(e.xmaprequest); + break; + case DestroyNotify: + destroyNotify(e.xdestroywindow); + break; + case EnterNotify: + enterNotify(e.xcrossing); + break; + case ClientMessage: + clientMessage(e.xclient); + break; + default: + // cout << "Unhandled event: " << getEventName(e.type) << endl; + break; + } + } + } + if(ready == -1) + { + cout << "E" << endl; + log("ERROR"); + } + } + + //Kill children + ipc.quitIPC(); + XCloseDisplay(dpy); +} diff --git a/src/structs.h b/src/structs.h new file mode 100644 index 0000000..8215bf5 --- /dev/null +++ b/src/structs.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include +#include +#include + +#define noID -1 + +struct Client +{ + int ID; + Window w; + bool floating; + bool fullscreen; +}; + +enum TileDir +{ + horizontal, + vertical, + noDir +}; + +struct Frame +{ + int ID; + int pID; + + bool isClient; + + //If its a client (window) + int cID; + + //If it isn't a client + TileDir dir; + std::vector subFrameIDs; + bool isRoot; + std::vector floatingFrameIDs; + //int whichChildFocused = 0; +}; + +struct ScreenInfo +{ + std::string name; + int x, y, w, h; +}; diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..58116d0 --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,32 @@ +#include "util.h" + +#include +#include + +using std::string; + +std::vector split (const string &s, char delim) { + std::vector result; + std::stringstream ss (s); + string item; + + while (getline (ss, item, delim)) { + result.push_back (item); + } + + return result; +} + +const string evNames[] = {"", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent", "LASTEvent"}; + +string getEventName(int e) +{ + return evNames[e]; +} + +string lowercase(string s) +{ + string s2 = s; + std::transform(s2.begin(), s2.end(), s2.begin(), [](unsigned char c){ return std::tolower(c); }); + return s2; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..66ecf76 --- /dev/null +++ b/src/util.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + + +std::string getEventName(int e); + + +std::vector split (const std::string &s, char delim); + +std::string lowercase(std::string s); + + +struct Globals { + Display*& dpy; + Window& root; +}; diff --git a/structs.h b/structs.h deleted file mode 100644 index 8215bf5..0000000 --- a/structs.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -#define noID -1 - -struct Client -{ - int ID; - Window w; - bool floating; - bool fullscreen; -}; - -enum TileDir -{ - horizontal, - vertical, - noDir -}; - -struct Frame -{ - int ID; - int pID; - - bool isClient; - - //If its a client (window) - int cID; - - //If it isn't a client - TileDir dir; - std::vector subFrameIDs; - bool isRoot; - std::vector floatingFrameIDs; - //int whichChildFocused = 0; -}; - -struct ScreenInfo -{ - std::string name; - int x, y, w, h; -}; diff --git a/test b/test index 49cbf49..fba98d4 100644 --- a/test +++ b/test @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash make diff --git a/util.cpp b/util.cpp deleted file mode 100644 index 58116d0..0000000 --- a/util.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "util.h" - -#include -#include - -using std::string; - -std::vector split (const string &s, char delim) { - std::vector result; - std::stringstream ss (s); - string item; - - while (getline (ss, item, delim)) { - result.push_back (item); - } - - return result; -} - -const string evNames[] = {"", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent", "LASTEvent"}; - -string getEventName(int e) -{ - return evNames[e]; -} - -string lowercase(string s) -{ - string s2 = s; - std::transform(s2.begin(), s2.end(), s2.begin(), [](unsigned char c){ return std::tolower(c); }); - return s2; -} diff --git a/util.h b/util.h deleted file mode 100644 index 66ecf76..0000000 --- a/util.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include -#include - - -std::string getEventName(int e); - - -std::vector split (const std::string &s, char delim); - -std::string lowercase(std::string s); - - -struct Globals { - Display*& dpy; - Window& root; -}; -- cgit v1.2.3