diff --git a/CMakeLists.txt b/CMakeLists.txt index 144e9bb..069772b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,27 +4,41 @@ project(Wmderland) # Request C++11 standard, using new CMake variables. set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -Wall") # There are two CMake scripts in ./cmake # 1. BuildType.cmake - determine build type on demand # 2. Findglog.cmake - used by `find_package(glog REQUIRED)` set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") -# Load and run CMake code from a file or module. +# Determine BuildType on demand. include(BuildType) -# Add some extra flags to g++ -# -flto: runs the standard link-time optimizer -# -Wall: "warn all" turns on almost all warning -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -Wall") - +# Find the required libraries. find_package(X11 REQUIRED) find_package(glog REQUIRED) +# Automatic macro construction. +set(VERSION_MAJOR 0) +set(VERSION_MINOR 9) + +# CMake will generate config.hpp from config.hpp.in +# and store it under src/ +configure_file( + "${PROJECT_SOURCE_DIR}/src/config.hpp.in" + "${PROJECT_SOURCE_DIR}/src/config.hpp" +) + + # Grab all files end in .cpp FILE(GLOB cpp_sources src/*.cpp) add_executable(Wmderland ${cpp_sources}) -target_link_libraries(Wmderland X11 glog) + +set(LIBRARIES "X11") +if(GLOG_FOUND) + set(LIBRARIES "${LIBRARIES} glog") +endif() +target_link_libraries(Wmderland X11 ${LIBRARIES}) # Install rule -install (TARGETS Wmderland DESTINATION bin) +install(TARGETS Wmderland DESTINATION bin) diff --git a/cmake/Findglog.cmake b/cmake/Findglog.cmake index 8e86bef..caffde6 100644 --- a/cmake/Findglog.cmake +++ b/cmake/Findglog.cmake @@ -42,9 +42,8 @@ endif() find_package_handle_standard_args(Glog DEFAULT_MSG GLOG_INCLUDE_DIR GLOG_LIBRARY) if(GLOG_FOUND) - set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR}) - set(GLOG_LIBRARIES ${GLOG_LIBRARY}) - message(STATUS "Found glog (include: ${GLOG_INCLUDE_DIR}, library: ${GLOG_LIBRARY})") - mark_as_advanced(GLOG_ROOT_DIR GLOG_LIBRARY_RELEASE GLOG_LIBRARY_DEBUG - GLOG_LIBRARY GLOG_INCLUDE_DIR) + set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR}) + set(GLOG_LIBRARIES ${GLOG_LIBRARY}) + message(STATUS "Found glog (include: ${GLOG_INCLUDE_DIR}, library: ${GLOG_LIBRARY})") + mark_as_advanced(GLOG_ROOT_DIR GLOG_LIBRARY_RELEASE GLOG_LIBRARY_DEBUG GLOG_LIBRARY GLOG_INCLUDE_DIR) endif() diff --git a/src/config.cpp b/src/config.cpp index 29f7419..20a2426 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,9 +1,11 @@ #include "action.hpp" #include "config.hpp" #include "util.hpp" -#include #include #include +#if GLOG_FOUND != FALSE +#include +#endif using std::hex; using std::pair; @@ -71,7 +73,9 @@ Config::Config(Display* dpy, Properties* prop, string filename) : dpy_(dpy), pro autostart_rules_.push_back(cmd); break; } default: { - LOG(INFO) << "Ignored unrecognized symbol in config: " << tokens[0]; + #if GLOG_FOUND != FALSE + LOG(INFO) << "Ignored unrecognized symbol in config: " << tokens[0]; + #endif break; } } diff --git a/src/config.hpp b/src/config.hpp index 2e5cdd4..3cd5b3c 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -28,6 +28,10 @@ #define VARIABLE_PREFIX "$" #define DEFAULT_EXIT_KEY "Mod4+Shift+Escape" +// The following macro will be generated by CMake which determines if Glog +// is installed on the machine used to compile Wmderland. +#define GLOG_FOUND TRUE + enum class ConfigKeyword { SET, ASSIGN, diff --git a/src/config.hpp.in b/src/config.hpp.in new file mode 100644 index 0000000..eb421f5 --- /dev/null +++ b/src/config.hpp.in @@ -0,0 +1,95 @@ +#ifndef WMDERLAND_CONFIG_HPP_ +#define WMDERLAND_CONFIG_HPP_ + +#include "action.hpp" +#include "util.hpp" +#include +#include +#include + +#define WIN_MGR_NAME "Wmderland" +#define VERSION "0.9.1 Beta" +#define CONFIG_FILE "~/.config/Wmderland/config" +#define COOKIE_FILE "~/.local/share/Wmderland/cookie" + +#define WORKSPACE_UNSPECIFIED -1 +#define WORKSPACE_COUNT 9 + +#define MIN_WINDOW_WIDTH 50 +#define MIN_WINDOW_HEIGHT 50 +#define DEFAULT_FLOATING_WINDOW_WIDTH 800 +#define DEFAULT_FLOATING_WINDOW_HEIGHT 600 + +#define DEFAULT_GAP_WIDTH 15 +#define DEFAULT_BORDER_WIDTH 3 +#define DEFAULT_FOCUSED_COLOR 0xffffffff +#define DEFAULT_UNFOCUSED_COLOR 0xff41485f + +#define VARIABLE_PREFIX "$" +#define DEFAULT_EXIT_KEY "Mod4+Shift+Escape" + +// The following macro will be generated by CMake which determines if Glog +// is installed on the machine used to compile Wmderland. +#define GLOG_FOUND @GLOG_FOUND@ + +enum class ConfigKeyword { + SET, + ASSIGN, + FLOATING, + PROHIBIT, + BINDSYM, + EXEC, + UNDEFINED +}; + +class Config { +public: + Config(Display* dpy, Properties* prop, std::string filename); + virtual ~Config(); + + int GetSpawnWorkspaceId(Window w) const; + bool ShouldFloat(Window w) const; + bool ShouldProhibit(Window w) const; + const std::vector& GetKeybindActions(const std::string& modifier, const std::string& key) const; + void SetKeybindActions(const std::string& modifier_and_key, const std::string& actions); + + unsigned short gap_width() const; + unsigned short border_width() const; + unsigned short min_window_width() const; + unsigned short min_window_height() const; + unsigned long focused_color() const; + unsigned long unfocused_color() const; + + const std::unordered_map& spawn_rules() const; + const std::unordered_map& float_rules() const; + const std::unordered_map& prohibit_rules() const; + const std::unordered_map>& keybind_rules() const; + const std::vector& autostart_rules() const; + +private: + static ConfigKeyword StrToConfigKeyword(const std::string& s); + static std::string ExtractWindowIdentifier(const std::string& s); + std::vector GeneratePossibleConfigKeys(Window w) const; + const std::string& ReplaceSymbols(std::string& s); + std::unordered_map symtab_; + + // Global variables + unsigned short gap_width_; + unsigned short border_width_; + unsigned short min_window_width_; + unsigned short min_window_height_; + unsigned long focused_color_; + unsigned long unfocused_color_; + + // Rules + std::unordered_map spawn_rules_; // spawn certain apps in certain workspaces. + std::unordered_map float_rules_; // start certain apps in floating mode. + std::unordered_map prohibit_rules_; // apps that should be prohibit from starting. + std::unordered_map> keybind_rules_; // keybind actions. + std::vector autostart_rules_; // launch certain apps when wm starts. + + Display* dpy_; + Properties* prop_; +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index e3f38fd..af61c01 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,12 @@ #include "wm.hpp" #include "config.hpp" -#include #include #include #include +#include +#if GLOG_FOUND != FALSE +#include +#endif using std::string; using std::unique_ptr; @@ -22,20 +25,26 @@ int main(int argc, char* args[]) { } try { - // Initialize google's c++ logging library. - google::InitGoogleLogging(args[0]); + #if GLOG_FOUND != FALSE + // Initialize google's c++ logging library. + google::InitGoogleLogging(args[0]); + #endif // WindowManager is a singleton class. If XOpenDisplay() fails during // WindowManager::GetInstance(), it will return None (in xlib, None is // the universal null resource ID or atom.) unique_ptr wm = WindowManager::GetInstance(); if (!wm) { - LOG(INFO) << "Failed to open display to X server."; + #if GLOG_FOUND != FALSE + LOG(INFO) << "Failed to open display to X server."; + #endif return EXIT_FAILURE; } wm->Run(); } catch (const std::exception& ex) { - LOG(ERROR) << ex.what(); + #if GLOG_FOUND != FALSE + LOG(ERROR) << ex.what(); + #endif return EXIT_FAILURE; } diff --git a/src/wm.cpp b/src/wm.cpp index f48fd4b..66f3d70 100644 --- a/src/wm.cpp +++ b/src/wm.cpp @@ -1,16 +1,19 @@ #include "wm.hpp" #include "client.hpp" #include "util.hpp" +#include +#include +#include +#include +#include extern "C" { #include #include #include } +#if GLOG_FOUND != FALSE #include -#include -#include -#include -#include +#endif using std::hex; using std::find; @@ -407,16 +410,18 @@ void WindowManager::OnClientMessage(const XClientMessageEvent& e) { } int WindowManager::OnXError(Display* dpy, XErrorEvent* e) { - const int MAX_ERROR_TEXT_LENGTH = 1024; - char error_text[MAX_ERROR_TEXT_LENGTH]; - XGetErrorText(dpy, e->error_code, error_text, sizeof(error_text)); - LOG(ERROR) << "Received X error:\n" - << " Request: " << int(e->request_code) - << " Error code: " << int(e->error_code) - << " - " << error_text << "\n" - << " Resource ID: " << e->resourceid; - // The return value is ignored. - return 0; + #if GLOG_FOUND != FALSE + const int MAX_ERROR_TEXT_LENGTH = 1024; + char error_text[MAX_ERROR_TEXT_LENGTH]; + XGetErrorText(dpy, e->error_code, error_text, sizeof(error_text)); + LOG(ERROR) << "Received X error:\n" + << " Request: " << int(e->request_code) + << " Error code: " << int(e->error_code) + << " - " << error_text << "\n" + << " Resource ID: " << e->resourceid; + // The return value is ignored. + return 0; + #endif } @@ -554,7 +559,7 @@ void WindowManager::KillClient(Window w) { msg.xclient.window = w; msg.xclient.format = 32; msg.xclient.data.l[0] = prop_->wm[atom::WM_DELETE]; - CHECK(XSendEvent(dpy_, w, false, 0, &msg)); + XSendEvent(dpy_, w, false, 0, &msg); } else { XKillClient(dpy_, w); }