├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── app_menu.cpp ├── app_menu.h ├── compile_commands.json ├── indicator.cpp ├── indicator.h ├── main.cpp ├── power_profile_manager.cpp ├── power_profile_manager.h └── screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | .cache/clangd/index 2 | build 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(powermode-indicator VERSION 0.1.1) 3 | 4 | enable_language(CXX) 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_EXPORT_COMPILE_COMMANDS 1) 7 | 8 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -ggdb3") 9 | set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -ggdb3") 10 | 11 | find_package(PkgConfig REQUIRED) 12 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtkmm-3.0 glibmm-2.4 giomm-2.4) 13 | pkg_check_modules(APP_INDICATOR REQUIRED IMPORTED_TARGET appindicator3-0.1) 14 | 15 | add_executable(powermode-indicator main.cpp app_menu.cpp 16 | power_profile_manager.cpp indicator.cpp) 17 | 18 | target_link_libraries(powermode-indicator ${GTK_LIBRARIES} 19 | ${APP_INDICATOR_LIBRARIES}) 20 | 21 | target_compile_options( 22 | powermode-indicator PRIVATE ${GTK_CFLAGS_OTHER} ${APP_INDICATOR_CFLAGS_OTHER}) 23 | 24 | target_include_directories( 25 | powermode-indicator PRIVATE ${GTK_INCLUDE_DIRS} ${APP_INDICATOR_INCLUDE_DIRS}) 26 | 27 | target_link_directories(powermode-indicator PRIVATE ${GTK_LIBRARY_DIRS} 28 | ${APP_INDICATOR_LIBRARIES}) 29 | 30 | install(TARGETS powermode-indicator DESTINATION bin) 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 Piyush Raj 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Powermode Indicator 2 | 3 | It is a plugin for all desktops supported by libappindicator. It provides menu to choose power profiles. 4 | 5 | I do use it on my system. I would love to see contributions and bug reports. 6 | 7 | > It depends on [power-profiles-daemon](https://archlinux.org/packages/extra/x86_64/power-profiles-daemon/) 8 | 9 | ![How many is shown](./screenshot.png) 10 | 11 | ## Installation 12 | 13 | ### Arch Linux 14 | ``` bash 15 | paru -S powermode-indicator-git 16 | ``` 17 | 18 | ### Ubuntu and Debian 19 | 20 | Deb file has been provided in release. You can download and install. 21 | 22 | ### From sources 23 | 24 | > The packages is made using cmake 25 | 26 | #### You will need following dependencies: 27 | 28 | * cmake > 3.16 29 | * gtkmm-3.0 30 | * glibmm-2.4 31 | * giomm-2.4 32 | * appindicator3-0.1 33 | * gcc or clangd 34 | * pkg-config 35 | 36 | #### Steps: 37 | 38 | * Clone and change to the project directory 39 | ``` 40 | cd powermode-indicator 41 | ``` 42 | * Make a build directory 43 | ``` bash 44 | mkdir build 45 | ``` 46 | * To build run following commands 47 | ``` bash 48 | cmake -B build -S . 49 | cmake --build build 50 | ``` 51 | * To install run following commands 52 | ``` bash 53 | cmake --install build 54 | ``` 55 | 56 | ## How to run and configure? 57 | 58 | The indicator shows up in Status Tray once `powermode-indicator` command is executed. 59 | 60 | I would recommend you to add it in autostart script. 61 | 62 | ## Troubleshoot 63 | 64 | * The indicator doesn't show performace mode or other mode if that is not available on your laptop. If you are not sure run the follwing command to check 65 | ``` bash 66 | powerprofilesctl 67 | ``` 68 | * If icons are not shown. Try papirus-icon-theme, breeze-icons or any other complete icon pack 69 | -------------------------------------------------------------------------------- /app_menu.cpp: -------------------------------------------------------------------------------- 1 | #include "app_menu.h" 2 | #include 3 | #include 4 | 5 | void run() {} 6 | 7 | AppMenu::AppMenu(std::shared_ptr indicator) 8 | : m_performance_menu_item("Performance"), m_balanced_menu_item("Balanced"), 9 | m_power_saver_menu_item("Power Saver"), m_group1(), 10 | m_power_profile_manager(), m_current_profile("balanced") { 11 | auto profiles_available = m_power_profile_manager.get_all(); 12 | m_indicator = indicator; 13 | 14 | m_balanced_menu_item.set_group(m_group1); 15 | m_power_saver_menu_item.set_group(m_group1); 16 | m_performance_menu_item.set_group(m_group1); 17 | 18 | if (std::find(profiles_available.begin(), profiles_available.end(), 19 | "balanced") != profiles_available.end()) 20 | add(m_balanced_menu_item); 21 | if (std::find(profiles_available.begin(), profiles_available.end(), 22 | "power-saver") != profiles_available.end()) 23 | add(m_power_saver_menu_item); 24 | if (std::find(profiles_available.begin(), profiles_available.end(), 25 | "performance") != profiles_available.end()) 26 | add(m_performance_menu_item); 27 | this->update(); 28 | 29 | Glib::signal_timeout().connect( 30 | [this]() { 31 | auto active_profile = this->m_power_profile_manager.get_profile(); 32 | if (this->m_current_profile != active_profile) { 33 | this->m_current_profile = active_profile; 34 | this->update(); 35 | } 36 | return true; 37 | }, 38 | 1000); 39 | show_all(); 40 | 41 | m_balanced_menu_item.signal_activate().connect( 42 | [this]() { this->m_power_profile_manager.set_profile("balanced"); }); 43 | 44 | m_power_saver_menu_item.signal_activate().connect( 45 | [this]() { this->m_power_profile_manager.set_profile("power-saver"); }); 46 | 47 | m_performance_menu_item.signal_activate().connect( 48 | [this]() { this->m_power_profile_manager.set_profile("performance"); }); 49 | } 50 | 51 | AppMenu::~AppMenu() {} 52 | 53 | void AppMenu::update() { 54 | if (this->m_current_profile == "balanced") { 55 | m_indicator.get()->change_icon("speedometer"); 56 | this->m_balanced_menu_item.set_active(); 57 | } else if (this->m_current_profile == "power-saver") { 58 | m_indicator.get()->change_icon("battery-profile-powersave"); 59 | this->m_power_saver_menu_item.set_active(); 60 | } else if (this->m_current_profile == "performance") { 61 | m_indicator.get()->change_icon("battery-profile-performance"); 62 | this->m_performance_menu_item.set_active(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app_menu.h: -------------------------------------------------------------------------------- 1 | #ifndef APP_MENU_H 2 | #define APP_MENU_H 3 | 4 | #include "indicator.h" 5 | #include "power_profile_manager.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class AppMenu : public Gtk::Menu { 12 | public: 13 | AppMenu(std::shared_ptr indicator); 14 | virtual ~AppMenu(); 15 | 16 | private: 17 | std::shared_ptr m_indicator; 18 | 19 | Gtk::RadioButtonGroup m_group1; 20 | 21 | Gtk::RadioMenuItem m_performance_menu_item; 22 | Gtk::RadioMenuItem m_balanced_menu_item; 23 | Gtk::RadioMenuItem m_power_saver_menu_item; 24 | 25 | PowerProfileManager m_power_profile_manager; 26 | 27 | Glib::ustring m_current_profile; 28 | 29 | void update(); 30 | }; 31 | 32 | #endif // !APP_MENU_H 33 | -------------------------------------------------------------------------------- /compile_commands.json: -------------------------------------------------------------------------------- 1 | build/compile_commands.json -------------------------------------------------------------------------------- /indicator.cpp: -------------------------------------------------------------------------------- 1 | #include "indicator.h" 2 | 3 | Indicator::Indicator() 4 | : m_app_indicator(app_indicator_new("powermode-indicator", "", 5 | APP_INDICATOR_CATEGORY_HARDWARE)) { 6 | app_indicator_set_status(m_app_indicator.get(), APP_INDICATOR_STATUS_ACTIVE); 7 | 8 | g_assert(IS_APP_INDICATOR(m_app_indicator.get())); 9 | g_assert(G_IS_OBJECT(m_app_indicator.get())); 10 | } 11 | 12 | Indicator::~Indicator() {} 13 | 14 | void Indicator::add_menu(Gtk::Menu &menu) { 15 | app_indicator_set_menu(m_app_indicator.get(), menu.gobj()); 16 | } 17 | 18 | void Indicator::change_icon(std::string icon) { 19 | app_indicator_set_icon(m_app_indicator.get(), icon.c_str()); 20 | } 21 | -------------------------------------------------------------------------------- /indicator.h: -------------------------------------------------------------------------------- 1 | #ifndef APP_INDICATOR_H 2 | #define APP_INDICATOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class Indicator { 11 | public: 12 | Indicator(); 13 | ~Indicator(); 14 | 15 | void add_menu(Gtk::Menu &); 16 | void change_icon(std::string icon); 17 | 18 | private: 19 | std::unique_ptr m_app_indicator; 20 | }; 21 | 22 | #endif // !APP_INDICATOR_H 23 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "app_menu.h" 2 | #include "indicator.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char *argv[]) { 10 | mtrace(); 11 | 12 | Glib::RefPtr app = Gtk::Application::create(argc, argv); 13 | 14 | std::shared_ptr indicator(new Indicator); 15 | 16 | AppMenu app_menu(indicator); 17 | 18 | indicator.get()->add_menu(app_menu); 19 | 20 | Glib::RefPtr loop = Glib::MainLoop::create(); 21 | loop->run(); 22 | 23 | muntrace(); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /power_profile_manager.cpp: -------------------------------------------------------------------------------- 1 | #include "power_profile_manager.h" 2 | 3 | #include 4 | 5 | #define assert_ambiguous_output(condition, data, ret) \ 6 | if (condition) { \ 7 | std::cerr << "Dbus output is ambiguous!" << std::endl; \ 8 | std::cerr << data.print(); \ 9 | return ret; \ 10 | } 11 | 12 | PowerProfileManager::PowerProfileManager() { 13 | Gio::init(); 14 | Glib::RefPtr connection = 15 | Gio::DBus::Connection::get_sync(Gio::DBus::BusType::BUS_TYPE_SYSTEM); 16 | 17 | if (!connection) { 18 | std::cerr << "System Bus not available" << std::endl; 19 | exit(1); 20 | } 21 | 22 | this->m_proxy = Gio::DBus::Proxy::create_sync( 23 | connection, "org.freedesktop.UPower.PowerProfiles", 24 | "/org/freedesktop/UPower/PowerProfiles", 25 | "org.freedesktop.DBus.Properties"); 26 | } 27 | 28 | PowerProfileManager::~PowerProfileManager() {} 29 | 30 | Glib::ustring PowerProfileManager::get_profile() { 31 | std::vector params; 32 | params.push_back(Glib::Variant::create( 33 | "org.freedesktop.UPower.PowerProfiles")); 34 | params.push_back(Glib::Variant::create("ActiveProfile")); 35 | auto params_container = Glib::VariantContainerBase::create_tuple(params); 36 | auto result = this->m_proxy->call_sync("Get", params_container); 37 | 38 | assert_ambiguous_output(result.get_type_string() != "(v)", result, ""); 39 | Glib::Variant profile; 40 | assert_ambiguous_output( 41 | !Glib::VariantIter(result.get_child()).next_value(profile), result, ""); 42 | return profile.get(); 43 | } 44 | 45 | void PowerProfileManager::set_profile(Glib::ustring profile) { 46 | std::vector params; 47 | params.push_back(Glib::Variant::create( 48 | "org.freedesktop.UPower.PowerProfiles")); 49 | params.push_back(Glib::Variant::create("ActiveProfile")); 50 | params.push_back(Glib::Variant>::create( 51 | Glib::Variant( 52 | Glib::Variant::create(profile)))); 53 | auto params_container = Glib::VariantContainerBase::create_tuple(params); 54 | auto result = this->m_proxy->call_sync("Set", params_container); 55 | assert_ambiguous_output(result.get_type_string() != "()", result, ); 56 | assert_ambiguous_output(Glib::VariantIter(result).get_n_children() != 0, 57 | result, ); 58 | } 59 | 60 | std::vector PowerProfileManager::get_all() { 61 | std::vector profiles_available; 62 | 63 | std::vector params; 64 | params.push_back(Glib::Variant::create( 65 | "org.freedesktop.UPower.PowerProfiles")); 66 | auto params_container = Glib::VariantContainerBase::create_tuple(params); 67 | auto result = this->m_proxy->call_sync("GetAll", params_container); 68 | 69 | assert_ambiguous_output(result.get_type_string() != "(a{sv})", result, 70 | profiles_available); 71 | 72 | Glib::Variant> main_struct; 73 | result.get_child(main_struct); 74 | assert_ambiguous_output(main_struct.get().count("Profiles") != 1, result, 75 | profiles_available); 76 | 77 | Glib::VariantIter profiles((main_struct.get())["Profiles"]); 78 | Glib::Variant> profile; 79 | while (profiles.next_value(profile)) { 80 | assert_ambiguous_output(profile.get().count("Profile") != 1, result, 81 | profiles_available); 82 | auto prof = Glib::VariantBase::cast_dynamic>( 83 | (profile.get())["Profile"]); 84 | profiles_available.push_back(prof.get()); 85 | } 86 | 87 | return profiles_available; 88 | } 89 | -------------------------------------------------------------------------------- /power_profile_manager.h: -------------------------------------------------------------------------------- 1 | #ifndef POWER_PROFILE_MANAGER 2 | #define POWER_PROFILE_MANAGER 3 | 4 | #include 5 | #include 6 | 7 | class PowerProfileManager { 8 | public: 9 | PowerProfileManager(); 10 | 11 | ~PowerProfileManager(); 12 | 13 | Glib::ustring get_profile(); 14 | void set_profile(Glib::ustring profile); 15 | std::vector get_all(); 16 | 17 | private: 18 | Glib::RefPtr m_proxy; 19 | }; 20 | 21 | #endif // !POWER_PROFILE_MANAGER 22 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PiyushXCoder/powermode-indicator/0a67f63290b087f1eeff2c6c6869c2122ac78e6f/screenshot.png --------------------------------------------------------------------------------