diff --git a/README.md b/README.md index 82b36488..7bb454c0 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ problems by [creating an issue ticket](https://github.com/jaagr/lemonbuddy/issue The main purpose of **Lemonbuddy** is to help users create awesome status bars. It has built-in functionality to generate content for the most commonly used widgets, such as: +- Window title - Playback controls and status display for [MPD](https://www.musicpd.org/) using [libmpdclient](https://www.musicpd.org/libs/libmpdclient/) - [ALSA](http://www.alsa-project.org/main/index.php/Main_Page) volume controls - Workspace and desktop panel for [bspwm](https://github.com/baskerville/bspwm) and [i3](https://github.com/i3/i3) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index c5df1e67..0cc7750a 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -3,7 +3,7 @@ # set(MODULES_LEFT "bspwm i3 mpd") -set(MODULES_CENTER "") +set(MODULES_CENTER "xwindow") set(MODULES_RIGHT "backlight volume memory cpu wlan eth battery temperature date powermenu") # Strip disabled modules {{{ diff --git a/examples/config b/examples/config index 7f4ed9d9..80aaf563 100644 --- a/examples/config +++ b/examples/config @@ -41,7 +41,7 @@ font-1 = unifont:size=6:heavy;-2 font-2 = siji:pixelsize=10;0 modules-left = bspwm i3 mpd -modules-center = +modules-center = xwindow modules-right = backlight volume memory cpu wlan eth battery temperature date powermenu tray-position = right @@ -52,6 +52,12 @@ tray-padding = 4 ;wm-restack = bspwm +[module/xwindow] +type = internal/xwindow +label = %title% +label-maxlen = 30 + + [module/filesystem] type = internal/fs interval = 25 diff --git a/examples/config.cmake b/examples/config.cmake index 6249a3bc..5d419026 100644 --- a/examples/config.cmake +++ b/examples/config.cmake @@ -52,6 +52,12 @@ tray-padding = 4 ;wm-restack = bspwm +[module/xwindow] +type = internal/xwindow +label = %title% +label-maxlen = 30 + + [module/filesystem] type = internal/fs interval = 25 diff --git a/include/drawtypes/label.hpp b/include/drawtypes/label.hpp index a95603f0..79ed8fd9 100644 --- a/include/drawtypes/label.hpp +++ b/include/drawtypes/label.hpp @@ -52,6 +52,7 @@ namespace drawtypes { operator bool(); label_t clone(); void reset_tokens(); + bool has_token(string token); void replace_token(string token, string replacement); void replace_defined_values(const label_t& label); void copy_undefined(const label_t& label); diff --git a/include/modules/xbacklight.hpp b/include/modules/xbacklight.hpp index bc51d640..6cdc82bb 100644 --- a/include/modules/xbacklight.hpp +++ b/include/modules/xbacklight.hpp @@ -32,6 +32,7 @@ namespace modules { using static_module::static_module; void setup(); + void teardown(); void handle(const evt::randr_notify& evt); void update(); string get_output(); diff --git a/include/modules/xwindow.hpp b/include/modules/xwindow.hpp new file mode 100644 index 00000000..c0f1b714 --- /dev/null +++ b/include/modules/xwindow.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include + +#include "components/config.hpp" +#include "drawtypes/label.hpp" +#include "modules/meta.hpp" +#include "x11/connection.hpp" +#include "x11/ewmh.hpp" +#include "x11/icccm.hpp" +#include "x11/window.hpp" + +LEMONBUDDY_NS + +namespace modules { + /** + * Wrapper used to update the event mask of the + * currently active to enable title tracking + */ + class active_window { + public: + explicit active_window(xcb_window_t win) + : m_connection(configure_connection().create()), m_window(m_connection, win) { + try { + m_window.change_event_mask(XCB_EVENT_MASK_PROPERTY_CHANGE); + } catch (const xpp::x::error::window& err) { + } + } + + ~active_window() { + try { + m_window.change_event_mask(XCB_EVENT_MASK_NO_EVENT); + } catch (const xpp::x::error::window& err) { + } + } + + /** + * Check if current window matches passed value + */ + bool match(const xcb_window_t win) const { + return m_window == win; + } + + /** + * Get the title by returning the first non-empty value of: + * _NET_WM_VISIBLE_NAME + * _NET_WM_NAME + */ + string title(xcb_ewmh_connection_t* ewmh) { + string title; + + if (!(title = ewmh_util::get_visible_name(ewmh, m_window)).empty()) { + return title; + } else if (!(title = icccm_util::get_wm_name(m_connection, m_window)).empty()) { + return title; + } else { + return ""; + } + } + + private: + connection& m_connection; + window m_window{m_connection}; + }; + + /** + * Module used to display information about the + * currently active X window. + */ + class xwindow_module : public static_module, public xpp::event::sink { + public: + using static_module::static_module; + + void setup(); + void teardown(); + void handle(const evt::property_notify& evt); + void update(); + string get_output(); + bool build(builder* builder, string tag) const; + + private: + static constexpr auto TAG_LABEL = "