diff --git a/CMakeLists.txt b/CMakeLists.txt index 463372a..0575cda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,14 +46,17 @@ file(GLOB_RECURSE HEADERS "include/logger/*.h" "include/logger/*.hpp") if(UNIX AND NOT APPLE) file(GLOB_RECURSE SOURCES "src/types/*.cpp" "src/platform/linux/*.cpp" "src/platform/shared/*.cpp" "src/ReWindow/*.cpp" ) + + find_package(PkgConfig REQUIRED) + pkg_check_modules(DBUS REQUIRED dbus-1) + include_directories("include" ${DBUS_INCLUDE_DIRS}) endif() if(WIN32) file(GLOB_RECURSE SOURCES "src/types/*.cpp" "src/platform/windows/*.cpp" "src/platform/shared/*.cpp" "src/ReWindow/*.cpp") + include_directories("include") endif() -include_directories("include") - if(UNIX) add_library(ReWindow SHARED ${SOURCES}) endif() @@ -68,7 +71,7 @@ target_include_directories(ReWindow PUBLIC ${Event_SOURCE_DIR}/include) set_target_properties(ReWindow PROPERTIES LINKER_LANGUAGE CXX) if(UNIX AND NOT APPLE) - target_link_libraries(ReWindow PUBLIC X11 Event jlog) + target_link_libraries(ReWindow PUBLIC X11 Event jlog ${DBUS_LIBRARIES}) target_link_libraries(ReWindow PUBLIC) add_executable(ReWindowDemo main.cpp) target_link_libraries(ReWindowDemo PUBLIC ReWindow) diff --git a/README.md b/README.md index 2d1aa4c..61e22bc 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ A library which allows easily creating and managing a window and it's events acr Install dependencies ```bash -Fedora/RHEL: dnf install cmake make gcc-g++ libX11 libX11-devel mesa-libGL-devel vulkan-loader-devel -Ubuntu/Debian: apt-get install cmake make gcc g++ libx11-6 libx11-dev libgl-dev libvulkan-dev libxrandr-dev +Fedora/RHEL: dnf install cmake make gcc-g++ libX11 libX11-devel mesa-libGL-devel vulkan-loader-devel dbus-devel +Ubuntu/Debian: apt-get install cmake make gcc g++ libx11-6 libx11-dev libgl-dev libvulkan-dev libxrandr-dev libdbus-1-dev ``` Clone the repository diff --git a/include/ReWindow/types/Window.h b/include/ReWindow/types/Window.h index 33e547a..89b6fa3 100644 --- a/include/ReWindow/types/Window.h +++ b/include/ReWindow/types/Window.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -371,6 +372,12 @@ public: /// @note If the window is already in focus when this is called nothing happens. void Flash(); + /// Sends a notification to the operating system notification area. + /// @param title The notification title. + /// @param content The actual text of the notification. + /// @param icon The path to the icon to be displayed on the notification, Empty for none. + bool Notify(const std::string& title, const std::string& content, const std::filesystem::path& icon = ""); + /// @returns True if we are definitely running on a software renderer. /// @note For some APIs this isn't typically possible. [[nodiscard]] virtual bool SoftwareRendered() { return false; } diff --git a/main.cpp b/main.cpp index c3fa5b3..d95d9df 100644 --- a/main.cpp +++ b/main.cpp @@ -48,6 +48,7 @@ int main() { auto* window = new MyWindow("Test Window", 600, 480); Logger::Debug(std::format("New window '{}' created. width={} height={}", window->GetTitle(), window->GetWidth(), window->GetHeight())); + window->Notify("Hello", "Test notification."); if (window->Open()) Logger::Debug(std::format("Opened window '{}'", window->GetTitle())); diff --git a/reci/scripts/builddeps.reci b/reci/scripts/builddeps.reci index ab12150..ee4c616 100644 --- a/reci/scripts/builddeps.reci +++ b/reci/scripts/builddeps.reci @@ -1 +1 @@ -Main:new("Install build dependencies", "apt-get install -yq libx11-6 libx11-dev libgl-dev libvulkan-dev") +Main:new("Install build dependencies", "apt-get install -yq libx11-6 libx11-dev libgl-dev libvulkan-dev libdbus-1-dev") diff --git a/src/platform/linux/Window.cpp b/src/platform/linux/Window.cpp index c0f4cfa..ae41201 100644 --- a/src/platform/linux/Window.cpp +++ b/src/platform/linux/Window.cpp @@ -7,6 +7,7 @@ #include #include #include +#include class ReWindow::RWindow::Platform { public: @@ -31,6 +32,65 @@ public: using namespace ReWindow; +bool RWindow::Notify(const std::string& title, const std::string& content, const std::filesystem::path& icon) { + DBusError db_error; + dbus_error_init(&db_error); + + DBusConnection* db_connection = dbus_bus_get(DBUS_BUS_SESSION, &db_error); + + if (!db_connection) { + dbus_error_free(&db_error); + return false; + } + + DBusMessage* db_message = dbus_message_new_method_call( + "org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications", + "Notify" + ); + + if (!db_message) + return false; + + const char* sender = this->title.c_str(); + uint32_t replaces_id = 0; + const char* app_icon = icon.c_str(); + const char* summary = title.c_str(); + const char* body = content.c_str(); + const char** actions = nullptr; + + DBusMessageIter db_args; + dbus_message_iter_init_append(db_message, &db_args); + + dbus_message_iter_append_basic(&db_args, DBUS_TYPE_STRING, &sender); + dbus_message_iter_append_basic(&db_args, DBUS_TYPE_UINT32, &replaces_id); + dbus_message_iter_append_basic(&db_args, DBUS_TYPE_STRING, &app_icon); + dbus_message_iter_append_basic(&db_args, DBUS_TYPE_STRING, &summary); + dbus_message_iter_append_basic(&db_args, DBUS_TYPE_STRING, &body); + + DBusMessageIter db_actions_array_iterator; + dbus_message_iter_open_container(&db_args, DBUS_TYPE_ARRAY, "s", &db_actions_array_iterator); + dbus_message_iter_close_container(&db_args, &db_actions_array_iterator); + + dbus_message_iter_open_container(&db_args, DBUS_TYPE_ARRAY, "{sv}", &db_actions_array_iterator); + dbus_message_iter_close_container(&db_args, &db_actions_array_iterator); + + int32_t notif_timeout = 5000; + dbus_message_iter_append_basic(&db_args, DBUS_TYPE_INT32, ¬if_timeout); + + DBusMessage* db_reply = dbus_connection_send_with_reply_and_block(db_connection, db_message, -1, &db_error); + dbus_message_unref(db_message); + + if (!db_reply) { + dbus_error_free(&db_error); + return false; + } + + dbus_message_unref(db_reply); + return true; +} + void RWindow::SetSize(const std::pair& size) { this->SetSize(size.first, size.second); }