commit 69b2cb0def00f1c5e6bf0507968bedfd0eb4ecc4 Author: Valentin Verdier Date: Mon Jul 13 00:37:45 2020 +0200 Commit initial diff --git a/src/Exception.cpp b/src/Exception.cpp new file mode 100644 index 0000000..4f5dc0c --- /dev/null +++ b/src/Exception.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include "Exception.hpp" + + +Kronos::Exception::Exception::Exception() : m_cause(nullptr) { + initTrace(); +} + +Kronos::Exception::Exception::Exception(const std::string& message) : m_cause(nullptr), m_message(message) { + initTrace(); +} + +Kronos::Exception::Exception::Exception(const std::string& message, const std::exception& cause) : m_cause(&cause), m_message(message) { + initTrace(); +} + +Kronos::Exception::Exception::Exception(const std::exception& cause) : m_cause(&cause) { + initTrace(); +} + +void Kronos::Exception::Exception::initTrace() { + std::stringstream ss; + + const std::string& msg = getMessage(); + + ss << typeid(*this).name(); + if(!msg.empty()) { + ss << " : " << msg; + } + if(m_cause != nullptr) { + ss << "\n -> " << m_cause->what(); + } + + m_trace = ss.str(); +} + +const char* Kronos::Exception::Exception::what() const noexcept { + return m_trace.c_str(); +} + +const std::exception* Kronos::Exception::Exception::getCause() const { + return m_cause; +} + +const std::string& Kronos::Exception::Exception::getMessage() const { + return m_message; +} diff --git a/src/Exception.hpp b/src/Exception.hpp new file mode 100644 index 0000000..1da38fd --- /dev/null +++ b/src/Exception.hpp @@ -0,0 +1,31 @@ +#ifndef KRONOS_EXCEPTION_HEADER +#define KRONOS_EXCEPTION_HEADER + +#include +#include + + +namespace Kronos { + namespace Exception { + class Exception : public std::exception { + private: + const std::exception* m_cause; + const std::string m_message; + std::string m_trace; + + void initTrace(); + + public: + Exception(); + Exception(const std::string& message); + Exception(const std::exception& cause); + Exception(const std::string& message, const std::exception& cause); + + const char* what() const noexcept; + const std::exception* getCause() const; + virtual const std::string& getMessage() const; + }; + } +} + +#endif diff --git a/src/IOException.hpp b/src/IOException.hpp new file mode 100644 index 0000000..bf53aa9 --- /dev/null +++ b/src/IOException.hpp @@ -0,0 +1,15 @@ +#ifndef KRONOS_IOEXCEPTION_HEADER +#define KRONOS_IOEXCEPTION_HEADER + +#include "Exception.hpp" + + +namespace Kronos { + namespace Exception { + class IOException : public Exception { + using Exception::Exception; + }; + } +} + +#endif diff --git a/src/Logger.cpp b/src/Logger.cpp new file mode 100644 index 0000000..277f98f --- /dev/null +++ b/src/Logger.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include "IOException.hpp" +#include "Logger.hpp" + + +Kronos::Logger* Kronos::Logger::s_instance = nullptr; + +void Kronos::Logger::Log(const std::string& msg) { + Kronos::Logger::Log(Kronos::Logger::Level::INFO, msg); +} + +void Kronos::Logger::Log(Kronos::Logger::Level level, const std::string& msg) { + assert(Kronos::Logger::s_instance != nullptr); + Kronos::Logger::s_instance->log(level, msg); +} + +Kronos::Logger::Logger(Kronos::Logger::Level level, const char* filename, bool console) + : m_level(level), m_console(console) { + assert(Kronos::Logger::s_instance == nullptr); + + if(filename != nullptr) { + m_logFile.open(filename, std::ofstream::app); + if(!m_logFile.is_open()) { + throw Kronos::Exception::IOException("Unable to open log file <" + std::string(filename) + ">"); + } + } + + Kronos::Logger::s_instance = this; +} + +Kronos::Logger::~Logger() { + if(m_logFile.is_open()) { + m_logFile.close(); + } + Kronos::Logger::s_instance = nullptr; +} + +void Kronos::Logger::setLevel(Kronos::Logger::Level level) { + m_level = level; +} + +void Kronos::Logger::log(Kronos::Logger::Level level, const std::string& msg) { + if(level <= m_level) { + time_t curTime = time(nullptr); + std::stringstream ss; + + char dtStr[20]; + strftime(dtStr, 20, "%Y-%m-%d %H:%M:%S", localtime(&curTime)); + + const char* lvlName = nullptr; + if(level == Kronos::Logger::Level::ERROR) { + lvlName = "ERROR"; + } else if(level == Kronos::Logger::Level::WARN) { + lvlName = "WARN"; + } else if(level == Kronos::Logger::Level::DEBUG) { + lvlName = "DEBUG"; + } else { + lvlName = "INFO"; + } + + ss << "[" << dtStr << "]" << "[" << lvlName << "] : " << msg; + + if(m_logFile.is_open()) { + m_logFile << ss.str() << std::endl; + } + + if(m_console) { + std::cout << ss.str() << std::endl; + } + } +} diff --git a/src/Logger.hpp b/src/Logger.hpp new file mode 100644 index 0000000..cdd33bb --- /dev/null +++ b/src/Logger.hpp @@ -0,0 +1,35 @@ +#ifndef KRONOS_LOGGER_HEADER +#define KRONOS_LOGGER_HEADER + +#include +#include + + +namespace Kronos { + class Logger final { + public: + enum Level {ERROR = 0, WARN = 1, INFO = 2, DEBUG = 3}; + + static void Log(const std::string& msg); + static void Log(Level level, const std::string& msg); + + Logger(Level level = Level::INFO, const char* filename = nullptr, bool console = true); + Logger(const Logger& logger) = delete; + ~Logger(); + + Logger& operator=(const Logger& logger) = delete; + + void setLevel(Level level); + + private: + void log(Level level, const std::string& msg); + + static Logger* s_instance; + + Level m_level; + std::ofstream m_logFile; + bool m_console; + }; +} + +#endif diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..1fea595 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,33 @@ +.PHONY: clean +CXX=g++ +CXXFLAGS_DEBUG:=$(CXXFLAGS) -Wall -std=c++17 -g +CXXFLAGS:=$(CXXFLAGS) -Wall -std=c++17 -O2 -s +LDFLAGS:=$(LDFLAGS) +INC_CXXFLAGS= +LIBS=-lX11 + +TARGETS=kronos +TARGETS_DEBUG=kronos_dbg +SRC=main.cpp Exception.cpp Logger.cpp XDisplayConnection.cpp XWindow.cpp +OBJ=$(SRC:.cpp=.o) +OBJ_DEBUG=$(SRC:.cpp=.odbg) + + +all: $(TARGETS) + +debug: $(TARGETS_DEBUG) + +kronos: $(OBJ) + $(CXX) $(LDFLAGS) $(LIBS) $^ -o $@ + +kronos_dbg: $(OBJ_DEBUG) + $(CXX) $(LDFLAGS) $(LIBS) $^ -o $@ + +%.o: %.cpp + $(CXX) $(CXXFLAGS) $(INC_CXXFLAGS) -c $^ -o $@ + +%.odbg: %.cpp + $(CXX) $(CXXFLAGS_DEBUG) $(INC_CXXFLAGS) -c $^ -o $@ + +clean: + rm -f $(TARGETS) $(TARGETS_DEBUG) $(OBJ) $(OBJ_DEBUG) diff --git a/src/WindowRecorder.hpp b/src/WindowRecorder.hpp new file mode 100644 index 0000000..80b45f4 --- /dev/null +++ b/src/WindowRecorder.hpp @@ -0,0 +1,13 @@ +#ifndef WINDOW_RECORDER_HEADER +#define WINDOW_RECORDER_HEADER + +namespace Kronos { + class WindowRecorder { + public: + virtual ~WindowRecorder() = 0; + + virtual prepare + }; +} + +#endif diff --git a/src/XDisplayConnection.cpp b/src/XDisplayConnection.cpp new file mode 100644 index 0000000..44b51b9 --- /dev/null +++ b/src/XDisplayConnection.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include "Logger.hpp" +#include "XWindow.hpp" +#include "XDisplayInitException.hpp" +#include "XDisplayConnection.hpp" + + +Kronos::XDisplayConnection::XDisplayConnection(const char* name) { + m_display = XOpenDisplay(name); + if(m_display == nullptr) { + throw Kronos::Exception::XDisplayInitException("Unable to open X display"); + } +} + +Kronos::XDisplayConnection::~XDisplayConnection() { + XCloseDisplay(m_display); +} + +Display* Kronos::XDisplayConnection::getDisplay() { + return m_display; +} + +std::vector Kronos::XDisplayConnection::getWindows() { + std::vector windows; + Atom propWin = XInternAtom(m_display, "_NET_CLIENT_LIST", False); + Atom type; + int form; + unsigned long remain, len; + unsigned char* prop = nullptr; + + if(XGetWindowProperty(m_display, XDefaultRootWindow(m_display), propWin, 0, 1024, False, XA_WINDOW, &type, &form, &len, &remain, &prop) == Success) { + Window* wins = (Window*) prop; + for(unsigned long i = 0; i < len; i++) { + windows.push_back(Kronos::XWindow(*this, wins[i])); + } + XFree(prop); + } else { + Kronos::Logger::Log(Kronos::Logger::Level::ERROR, "Unable to get windows list from XGetWindowProperty"); + } + + return windows; +} diff --git a/src/XDisplayConnection.hpp b/src/XDisplayConnection.hpp new file mode 100644 index 0000000..d420937 --- /dev/null +++ b/src/XDisplayConnection.hpp @@ -0,0 +1,26 @@ +#ifndef KRONOS_XDISPLAY_CONNECTION_HEADER +#define KRONOS_XDISPLAY_CONNECTION_HEADER + +#include +#include +#include "XWindow.hpp" + + +namespace Kronos { + class XDisplayConnection { + public: + XDisplayConnection(const char* name = nullptr); + XDisplayConnection(const XDisplayConnection& conn) = delete; + ~XDisplayConnection(); + + XDisplayConnection& operator=(const XDisplayConnection& conn) = delete; + + Display* getDisplay(); + std::vector getWindows(); + + private: + Display* m_display; + }; +} + +#endif diff --git a/src/XDisplayInitException.hpp b/src/XDisplayInitException.hpp new file mode 100644 index 0000000..35b4bee --- /dev/null +++ b/src/XDisplayInitException.hpp @@ -0,0 +1,15 @@ +#ifndef KRONOS_XDISPLAYINITEXCEPTION_HEADER +#define KRONOS_XDISPLAYINITEXCEPTION_HEADER + +#include "Exception.hpp" + + +namespace Kronos { + namespace Exception { + class XDisplayInitException : public Exception { + using Exception::Exception; + }; + } +} + +#endif diff --git a/src/XWindow.cpp b/src/XWindow.cpp new file mode 100644 index 0000000..c2ecf25 --- /dev/null +++ b/src/XWindow.cpp @@ -0,0 +1,63 @@ +#include +#include +#include +#include "XDisplayConnection.hpp" +#include "XWindowInitException.hpp" +#include "XWindow.hpp" + + +Kronos::XWindow::XWindow(Kronos::XDisplayConnection& conn, Window window) + : m_conn(conn), m_window(window) { + Atom propName = XInternAtom(m_conn.getDisplay(), "WM_NAME", False); + Atom type; + int form; + unsigned long remain, len; + unsigned char* prop = nullptr; + + if(XGetWindowProperty(m_conn.getDisplay(), m_window, propName, 0, 1024, False, AnyPropertyType, &type, &form, &len, &remain, &prop) == Success) { + m_name = (const char*) prop; + XFree(prop); + } + + XWindowAttributes attr; + if(!XGetWindowAttributes(m_conn.getDisplay(), m_window, &attr)) { + throw Kronos::Exception::XWindowInitException(); + } + m_width = attr.width; + m_height = attr.height; + + XSelectInput(m_conn.getDisplay(), m_window, StructureNotifyMask); + XSync(m_conn.getDisplay(), 0); +} + +Kronos::XWindow::~XWindow() { + XSelectInput(m_conn.getDisplay(), m_window, 0); +} + +void Kronos::XWindow::processEvents() { + /* + * IT DOES'T WORK !! + */ + + while(XEventsQueued(m_conn.getDisplay(), QueuedAfterReading) > 0) { + XEvent event; + XNextEvent(m_conn.getDisplay(), &event); + if(event.type == ConfigureNotify) { + XConfigureEvent conf = event.xconfigure; + m_width = conf.width; + m_height = conf.height; + } + } +} + +std::string Kronos::XWindow::getName() const { + return m_name; +} + +int Kronos::XWindow::getWidth() const { + return m_width; +} + +int Kronos::XWindow::getHeight() const { + return m_height; +} diff --git a/src/XWindow.hpp b/src/XWindow.hpp new file mode 100644 index 0000000..043ada2 --- /dev/null +++ b/src/XWindow.hpp @@ -0,0 +1,31 @@ +#ifndef KRONOS_XWINDOW_HEADER +#define KRONOS_XWINDOW_HEADER + +#include +#include +//#include "XDisplayConnection.hpp" + + +namespace Kronos { + class XDisplayConnection; + + class XWindow { + public: + XWindow(XDisplayConnection& conn, Window window); + ~XWindow(); + + void processEvents(); + std::string getName() const; + int getWidth() const; + int getHeight() const; + + private: + XDisplayConnection& m_conn; + Window m_window; + std::string m_name; + int m_width; + int m_height; + }; +} + +#endif diff --git a/src/XWindowInitException.hpp b/src/XWindowInitException.hpp new file mode 100644 index 0000000..f7e4cec --- /dev/null +++ b/src/XWindowInitException.hpp @@ -0,0 +1,15 @@ +#ifndef KRONOS_XWINDOWINITEXCEPTION_HEADER +#define KRONOS_XWINDOWINITEXCEPTION_HEADER + +#include "Exception.hpp" + + +namespace Kronos { + namespace Exception { + class XWindowInitException : public Exception { + using Exception::Exception; + }; + } +} + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..9112201 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,23 @@ +#include +#include +#include "Exception.hpp" +#include "Logger.hpp" +#include "XDisplayConnection.hpp" +#include "XWindow.hpp" + + +int main(int argc, char** argv) { + Kronos::Logger logger(Kronos::Logger::Level::INFO, "kronos.log"); + Kronos::Logger::Log("=============== Kronos v0.1 ==============="); + + Kronos::XDisplayConnection display; + std::vector windows = display.getWindows(); + + for(Kronos::XWindow& w : windows) { + w.processEvents(); + std::cout << "=> " << w.getName() << std::endl; + std::cout << " - " << w.getWidth() << "x" << w.getHeight() << std::endl; + } + + return 0; +}