├── .github └── workflows │ └── c-cpp.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── docs ├── CNAME ├── README.md ├── _config.yml ├── build.sh ├── powerkit.1 ├── powerkit.md └── screenshot.png ├── share ├── 90-backlight.rules ├── com.ubuntu.enable-hibernate.pkla ├── org.freedesktop.PowerManagement.Inhibit.xml ├── org.freedesktop.ScreenSaver.xml └── powerkit.desktop └── src ├── powerkit.cpp ├── powerkit_app.cpp ├── powerkit_app.h ├── powerkit_backlight.cpp ├── powerkit_backlight.h ├── powerkit_client.cpp ├── powerkit_client.h ├── powerkit_common.h ├── powerkit_cpu.cpp ├── powerkit_cpu.h ├── powerkit_device.cpp ├── powerkit_device.h ├── powerkit_dialog.cpp ├── powerkit_dialog.h ├── powerkit_manager.cpp ├── powerkit_manager.h ├── powerkit_notify.cpp ├── powerkit_notify.h ├── powerkit_powermanagement.cpp ├── powerkit_powermanagement.h ├── powerkit_screensaver.cpp ├── powerkit_screensaver.h ├── powerkit_settings.cpp ├── powerkit_settings.h ├── powerkit_theme.cpp └── powerkit_theme.h /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | os: [ubuntu-22.04] 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Install Dependencies 16 | run: sudo apt update && sudo apt install cmake qtbase5-dev libxss-dev libxrandr-dev 17 | - name: Build and Package 18 | run: | 19 | mkdir build && cd build 20 | cmake -DCMAKE_INSTALL_PREFIX=/usr -DSERVICE_GROUP=plugdev -DCMAKE_BUILD_TYPE=Release .. 21 | make -j2 22 | cpack -G DEB 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.user* 2 | build* 3 | *~ 4 | 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # PowerKit 2 | # Copyright (c) Ole-André Rodlie All rights reserved. 3 | # 4 | # Available under the 3-clause BSD license 5 | # See the LICENSE file for full details 6 | 7 | cmake_minimum_required(VERSION 3.14.3) 8 | 9 | project(powerkit VERSION 2.0.0 LANGUAGES CXX) 10 | 11 | set(PROJECT_HOMEPAGE_URL "https://github.com/rodlie/powerkit") 12 | set(PROJECT_DESCRIPTION "Power manager for alternative X11 desktop environments and window managers") 13 | 14 | set(CMAKE_CXX_STANDARD 11) 15 | set(CMAKE_AUTOMOC ON) 16 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 17 | 18 | # set version 19 | add_definitions(-DPOWERKIT_VERSION="${PROJECT_VERSION}") 20 | 21 | # debug/release 22 | add_compile_options(-Wall -Wextra) 23 | if(CMAKE_BUILD_TYPE MATCHES "^(release|Release|RELEASE)$") 24 | add_definitions(-DQT_NO_DEBUG_OUTPUT) 25 | else() 26 | add_definitions(-DQT_MESSAGELOGCONTEXT) 27 | endif() 28 | 29 | # qt 30 | find_package(QT NAMES Qt5 COMPONENTS Core REQUIRED) 31 | find_package( 32 | Qt${QT_VERSION_MAJOR} 33 | 5.15 34 | COMPONENTS 35 | Gui 36 | Widgets 37 | DBus 38 | REQUIRED 39 | ) 40 | 41 | # x11 42 | find_package(X11 REQUIRED) 43 | if(NOT X11_Xrandr_FOUND) 44 | message(FATAL_ERROR "Xrandr library not found") 45 | endif() 46 | if(NOT X11_Xss_FOUND) 47 | message(FATAL_ERROR "Xss library not found") 48 | endif() 49 | 50 | # setup adapters 51 | set(ADAPTERS) 52 | 53 | # org.freedesktop.PowerManagement.Inhibit 54 | qt_add_dbus_adaptor( 55 | ADAPTERS 56 | share/org.freedesktop.PowerManagement.Inhibit.xml 57 | ${PROJECT_NAME}_powermanagement.h 58 | PowerKit::PowerManagement 59 | InhibitAdaptor 60 | ) 61 | 62 | # org.freedesktop.ScreenSaver 63 | qt_add_dbus_adaptor( 64 | ADAPTERS 65 | share/org.freedesktop.ScreenSaver.xml 66 | ${PROJECT_NAME}_screensaver.h 67 | PowerKit::ScreenSaver 68 | ScreenSaverAdaptor 69 | ) 70 | 71 | # powerkit 72 | set(SOURCES 73 | src/${PROJECT_NAME}.cpp 74 | src/${PROJECT_NAME}_app.cpp 75 | src/${PROJECT_NAME}_backlight.cpp 76 | src/${PROJECT_NAME}_client.cpp 77 | src/${PROJECT_NAME}_cpu.cpp 78 | src/${PROJECT_NAME}_device.cpp 79 | src/${PROJECT_NAME}_dialog.cpp 80 | src/${PROJECT_NAME}_manager.cpp 81 | src/${PROJECT_NAME}_notify.cpp 82 | src/${PROJECT_NAME}_powermanagement.cpp 83 | src/${PROJECT_NAME}_screensaver.cpp 84 | src/${PROJECT_NAME}_settings.cpp 85 | src/${PROJECT_NAME}_theme.cpp 86 | ) 87 | set(HEADERS 88 | src/${PROJECT_NAME}_app.h 89 | src/${PROJECT_NAME}_backlight.h 90 | src/${PROJECT_NAME}_client.h 91 | src/${PROJECT_NAME}_common.h 92 | src/${PROJECT_NAME}_cpu.h 93 | src/${PROJECT_NAME}_device.h 94 | src/${PROJECT_NAME}_dialog.h 95 | src/${PROJECT_NAME}_manager.h 96 | src/${PROJECT_NAME}_notify.h 97 | src/${PROJECT_NAME}_powermanagement.h 98 | src/${PROJECT_NAME}_screensaver.h 99 | src/${PROJECT_NAME}_settings.h 100 | src/${PROJECT_NAME}_theme.h 101 | ) 102 | add_executable(${PROJECT_NAME} 103 | ${SOURCES} 104 | ${HEADERS} 105 | ${ADAPTERS} 106 | ) 107 | target_include_directories(${PROJECT_NAME} 108 | PRIVATE 109 | src 110 | ${X11_X11_INCLUDE_PATH} 111 | ${X11_Xrandr_INCLUDE_PATH} 112 | ${X11_Xss_INCLUDE_PATH}) 113 | target_link_libraries(${PROJECT_NAME} 114 | ${X11_LIBRARIES} 115 | ${X11_Xrandr_LIB} 116 | ${X11_Xss_LIB} 117 | Qt${QT_VERSION_MAJOR}::Core 118 | Qt${QT_VERSION_MAJOR}::DBus 119 | Qt${QT_VERSION_MAJOR}::Gui 120 | Qt${QT_VERSION_MAJOR}::Widgets) 121 | 122 | # desktop files 123 | configure_file(share/${PROJECT_NAME}.desktop 124 | ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.desktop 125 | @ONLY) 126 | 127 | # install 128 | include(GNUInstallDirs) 129 | install(TARGETS 130 | ${PROJECT_NAME} 131 | DESTINATION 132 | ${CMAKE_INSTALL_BINDIR}) 133 | install(FILES 134 | docs/${PROJECT_NAME}.1 135 | DESTINATION 136 | ${CMAKE_INSTALL_MANDIR}/man1) 137 | install(FILES 138 | ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.desktop 139 | DESTINATION 140 | ${CMAKE_INSTALL_DATAROOTDIR}/applications) 141 | install(FILES 142 | LICENSE 143 | DESTINATION 144 | ${CMAKE_INSTALL_DOCDIR}/${PROJECT_NAME}-${PROJECT_VERSION}) 145 | 146 | # package 147 | set(CPACK_SET_DESTDIR ON) 148 | set(CPACK_PACKAGE_CONTACT ${PROJECT_HOMEPAGE_URL}) 149 | set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") 150 | set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") 151 | set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") 152 | set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) 153 | set(CPACK_PACKAGE_DESCRIPTION ${PROJECT_DESCRIPTION}) 154 | set(CPACK_PACKAGE_VENDOR ${PROJECT_NAME}) 155 | set(CPACK_STRIP_FILES TRUE) 156 | 157 | set(CPACK_RPM_SPEC_MORE_DEFINE "%define _build_id_links none") 158 | set(CPACK_RPM_PACKAGE_LICENSE "BSD") 159 | set(CPACK_RPM_PACKAGE_URL ${PROJECT_HOMEPAGE_URL}) 160 | 161 | set(CPACK_DEBIAN_PACKAGE_DEPENDS "xsecurelock") 162 | set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) 163 | set(CPACK_DEBIAN_PACKAGE_HOMEPAGE ${PROJECT_HOMEPAGE_URL}) 164 | 165 | include(CPack) 166 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) Ole-André Rodlie 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | powerkit.dracolinux.org 2 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # powerkit 2 | 3 | Desktop independent power manager for use with alternative X11 desktop environments and window managers on Linux. 4 | 5 | ![Screenshot of the powerkit configuration](screenshot.png) 6 | 7 | * Implements *``org.freedesktop.ScreenSaver``* service 8 | * Implements *``org.freedesktop.PowerManagement.Inhibit``* service 9 | * Automatic actions on lid, idle and low battery 10 | * Sleep 11 | * Hibernate 12 | * HybridSleep 13 | * Suspend then Hibernate 14 | * Shutdown 15 | * Screen saver support 16 | * Screen lid support 17 | * Screen locking support 18 | * Screen backlight support 19 | * Notification support (can use *``org.freedesktop.Notifications``* if available) 20 | 21 | See [documentation](powerkit.md) (`man powerkit`) for more information. 22 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-hacker 2 | show_downloads: false 3 | -------------------------------------------------------------------------------- /docs/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | CWD=`pwd` 3 | 4 | if [ ! -f "${CWD}/CMakeLists.txt" ]; then 5 | echo "Run this script from the powerkit root directory" 6 | exit 1 7 | fi 8 | 9 | PANDOC=${PANDOC:-pandoc} 10 | MONTH=`echo $(LANG=en_us_88591; date "+%B")` 11 | YEAR=`echo $(LANG=en_us_88591; date "+%Y")` 12 | VERSION=`cat ${CWD}/CMakeLists.txt | sed '/powerkit VERSION/!d;s/)//' | awk '{print $3}'` 13 | echo "% POWERKIT(1) Version ${VERSION} | PowerKit Documentation" > ${CWD}/tmp.md 14 | echo "% Ole-André Rodlie" >> ${CWD}/tmp.md 15 | echo "% ${MONTH} ${YEAR}" >> ${CWD}/tmp.md 16 | cat ${CWD}/docs/powerkit.md >> ${CWD}/tmp.md 17 | ${PANDOC} ${CWD}/tmp.md -s -t man > ${CWD}/docs/powerkit.1 18 | rm ${CWD}/tmp.md 19 | -------------------------------------------------------------------------------- /docs/powerkit.1: -------------------------------------------------------------------------------- 1 | .\" Automatically generated by Pandoc 3.1.8 2 | .\" 3 | .TH "POWERKIT" "1" "February 2024" "Version 2.0.0" "PowerKit Documentation" 4 | .SH NAME 5 | \f[I]powerkit\f[R] - Desktop independent power manager for Linux 6 | .SH SYNOPSIS 7 | powerkit \f[I]\f[CI][--config]\f[I]\f[R] 8 | \f[I]\f[CI][--set-brightness-up]\f[I]\f[R] 9 | \f[I]\f[CI][--set-brightness-down]\f[I]\f[R] 10 | \f[I]\f[CI][--sleep]\f[I]\f[R] \f[I]\f[CI][--hibernate]\f[I]\f[R] 11 | \f[I]\f[CI][--lock]\f[I]\f[R] 12 | .SH DESCRIPTION 13 | Desktop independent power manager for use with alternative X11 desktop 14 | environments and window managers on Linux. 15 | .IP \[bu] 2 16 | Implements \f[I]\f[CI]org.freedesktop.ScreenSaver\f[I]\f[R] service 17 | .IP \[bu] 2 18 | Implements \f[I]\f[CI]org.freedesktop.PowerManagement.Inhibit\f[I]\f[R] 19 | service 20 | .IP \[bu] 2 21 | Automatic actions on lid, idle and low battery 22 | .RS 2 23 | .IP \[bu] 2 24 | Sleep 25 | .IP \[bu] 2 26 | Hibernate 27 | .IP \[bu] 2 28 | HybridSleep 29 | .IP \[bu] 2 30 | Suspend then Hibernate 31 | .IP \[bu] 2 32 | Shutdown 33 | .RE 34 | .IP \[bu] 2 35 | Screen saver support 36 | .IP \[bu] 2 37 | Screen lid support 38 | .IP \[bu] 2 39 | Screen locking support 40 | .IP \[bu] 2 41 | Screen backlight support 42 | .IP \[bu] 2 43 | Notification support (can use 44 | \f[I]\f[CI]org.freedesktop.Notifications\f[I]\f[R] if available) 45 | .SH USAGE 46 | powerkit should be started during the X11 user session. 47 | Consult the documentation for your desktop environment or window manager 48 | for launching startup applications. 49 | .IP \[bu] 2 50 | In \f[I]Fluxbox\f[R] add \f[I]\f[CI]powerkit &\f[I]\f[R] to the 51 | \f[I]\f[CI]\[ti]/.fluxbox/startup\f[I]\f[R] file 52 | .IP \[bu] 2 53 | In \f[I]Openbox\f[R] add \f[I]\f[CI]powerkit &\f[I]\f[R] to the 54 | \f[I]\f[CI]\[ti]/.config/openbox/autostart\f[I]\f[R] file. 55 | .PP 56 | \f[B]Do use powerkit if your desktop environment or window manager 57 | already has a power manager or screen saver service running.\f[R] 58 | .SS CONFIGURATION 59 | Settings are available directly from the system tray icon or run 60 | \f[I]\f[CI]powerkit --config\f[I]\f[R]. 61 | You should also be able to lauch the powerkit settings from your desktop 62 | application menu (if available). 63 | .SS SCREEN SAVER 64 | powerkit implements a basic screen saver to handle screen blanking, 65 | poweroff and locking feature. 66 | .PP 67 | Locking feature depends on \f[CR]xsecurelock\f[R]. 68 | .PP 69 | You can override the lock command with 70 | \f[I]\f[CI]screensaver_lock_cmd=\f[I]\f[R] in 71 | \f[I]\f[CI]\[ti]/.config/powerkit/powerkit.conf\f[I]\f[R]. 72 | Note that the command must not contain spaces. 73 | .SS BACKLIGHT 74 | The current display brightness (on laptops and supported displays) can 75 | be adjusted with the mouse wheel on the system tray icon or through the 76 | system tray menu. 77 | .PP 78 | powerkit also supports the following commands that can be used for 79 | global shortcuts, scripts etc: 80 | .TP 81 | \f[I]\f[CI]powerkit --set-brightness-up\f[I]\f[R] 82 | Set default display brightness up. 83 | .TP 84 | \f[I]\f[CI]powerkit --set-brightness-down\f[I]\f[R] 85 | Set default display brightness down. 86 | .PP 87 | On Fluxbox you can add the commands to the 88 | \f[I]\f[CI]\[ti]/.fluxbox/keys\f[I]\f[R] file: 89 | .IP 90 | .EX 91 | XF86MonBrightnessUp :Exec powerkit --set-brightness-up 92 | XF86MonBrightnessDown :Exec powerkit --set-brightness-down 93 | .EE 94 | .SS HIBERNATE 95 | If hibernate works depends on your system, a swap partition (or file) is 96 | needed by the kernel to support hibernate. 97 | .PP 98 | \f[B]\f[BI]Consult your system documentation regarding 99 | hibernation\f[B]\f[R]. 100 | .SS ICONS 101 | powerkit will use the existing icon theme from the running desktop 102 | environment or window manager. 103 | .PP 104 | You can override the icon theme in the 105 | \f[I]\f[CI]\[ti]/.config/powerkit/powerkit.conf\f[I]\f[R] file, use 106 | \f[I]\f[CI]icon_theme=\f[I]\f[R]. 107 | .SH FAQ 108 | .SS How does an application inhibit the screen saver? 109 | The preferred way to inhibit the screen saver from an application is to 110 | use the \f[I]org.freedesktop.ScreenSaver\f[R] specification. 111 | Any application that uses \f[I]org.freedesktop.ScreenSaver\f[R] will 112 | work with powerkit. 113 | .PP 114 | Popular applications that uses this feature is Mozilla Firefox, Google 115 | Chrome, VideoLAN VLC and many more. 116 | .SS How does an application inhibit suspend actions? 117 | The preferred way to inhibit suspend actions from an application is to 118 | use the \f[I]org.freedesktop.PowerManagement\f[R] specification. 119 | Any application that uses \f[I]org.freedesktop.PowerManagement\f[R] will 120 | work with powerkit. 121 | .PP 122 | Common use cases are audio playback, downloading, rendering and similar. 123 | .SS Google Chrome/Chromium does not inhibit the screen saver or power manager!? 124 | Chrome does not use \f[I]org.freedesktop.ScreenSaver\f[R] or 125 | \f[I]org.freedesktop.PowerManagement\f[R] until it detects a supported 126 | desktop environment. 127 | Add the following to \f[I]\f[CI]\[ti]/.bashrc\f[I]\f[R] or the 128 | \f[I]\f[CI]google-chrome\f[I]\f[R] launcher if you don\[cq]t run a 129 | supported desktop environment: 130 | .IP 131 | .EX 132 | export DESKTOP_SESSION=xfce 133 | export XDG_CURRENT_DESKTOP=xfce 134 | .EE 135 | .SS Mozilla Firefox does not inhibit the power manager during audio playback and/or downloading!? 136 | This is an issue with Firefox (missing feature). 137 | Use a different browser or open a request on the Firefox issue tracker. 138 | .PP 139 | Firefox should inhibit the power manager during audio playback 140 | (regardless of video) and during download (active queue). 141 | Currently Firefox only inhibit the screen saver during video playback. 142 | Chrome/Chromium does this correctly. 143 | .SH REQUIREMENTS 144 | powerkit requires the following dependencies: 145 | .IP \[bu] 2 146 | \f[I]X11 (https://www.x.org)\f[R] 147 | .IP \[bu] 2 148 | \f[I]libXss (https://www.x.org/archive//X11R7.7/doc/man/man3/Xss.3.xhtml)\f[R] 149 | .IP \[bu] 2 150 | \f[I]libXrandr (https://www.x.org/wiki/libraries/libxrandr/)\f[R] 151 | .IP \[bu] 2 152 | \f[I]Qt (https://qt.io)\f[R] 5.15 \f[I](Core/DBus/Gui/Widgets)\f[R] 153 | .IP \[bu] 2 154 | \f[I]logind (https://www.freedesktop.org/wiki/Software/systemd/logind/)\f[R] 155 | \f[I](or compatible service)\f[R] 156 | .IP \[bu] 2 157 | \f[I]UPower (https://upower.freedesktop.org/)\f[R] \f[I](or compatible 158 | service)\f[R] 159 | .IP \[bu] 2 160 | \f[I]xsecurelock (https://github.com/google/xsecurelock)\f[R] 161 | .SH BUILD 162 | First make sure you have the required dependencies installed, then 163 | review the most common build options: 164 | .IP \[bu] 2 165 | \f[I]\f[CI]CMAKE_INSTALL_PREFIX=\f[I]\f[R] - Install target. 166 | \f[I]\f[CI]/usr\f[I]\f[R] recommended. 167 | .IP \[bu] 2 168 | \f[I]\f[CI]CMAKE_BUILD_TYPE=\f[I]\f[R] - Build type. 169 | \f[I]\f[CI]Release\f[I]\f[R] recommended 170 | .PP 171 | Now configure powerkit with CMake and build: 172 | .IP 173 | .EX 174 | mkdir build && cd build 175 | cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release .. 176 | make -j4 177 | .EE 178 | .PP 179 | All you need is the \f[I]\f[CI]powerkit\f[I]\f[R] binary located in the 180 | build directory, you can run it from any location. 181 | .SS Install 182 | Use regular \f[I]\f[CI]make install\f[I]\f[R] with optional 183 | \f[I]\f[CI]DESTDIR\f[I]\f[R]: 184 | .IP 185 | .EX 186 | make DESTDIR= install 187 | .EE 188 | .PP 189 | or make a native package: 190 | .IP 191 | .EX 192 | cpack -G DEB 193 | .EE 194 | .IP 195 | .EX 196 | cpack -G RPM 197 | .EE 198 | .SH CHANGELOG 199 | .SS 2.0.0 (TBA) 200 | .IP \[bu] 2 201 | Recommended locker is \f[CR]xsecurelock\f[R] 202 | .IP \[bu] 2 203 | Added support for \[lq]modern\[rq] logind 204 | .IP \[bu] 2 205 | Removed support for ConsoleKit 206 | .IP \[bu] 2 207 | Removed support for XScreenSaver 208 | .IP \[bu] 2 209 | Added basic screen saver 210 | .IP \[bu] 2 211 | Easier to use (minimal/no setup) 212 | .IP \[bu] 2 213 | New UI 214 | .IP \[bu] 2 215 | Major code changes 216 | .SH OPTIONS 217 | .TP 218 | \f[I]\f[CI]--config\f[I]\f[R] 219 | Launch configuration. 220 | .TP 221 | \f[I]\f[CI]--set-brightness-up\f[I]\f[R] 222 | Set default display brightness up. 223 | .TP 224 | \f[I]\f[CI]--set-brightness-down\f[I]\f[R] 225 | Set default display brightness down. 226 | .TP 227 | \f[I]\f[CI]--sleep\f[I]\f[R] 228 | Suspend computer now. 229 | Can be combined with \f[I]\f[CI]--hibernate\f[I]\f[R] for suspend then 230 | hibernate after X amount of time. 231 | .TP 232 | \f[I]\f[CI]--hibernate\f[I]\f[R] 233 | Hibernate computer now. 234 | Can be combined with \f[I]\f[CI]--sleep\f[I]\f[R] for suspend then 235 | hibernate after X amount of time. 236 | .TP 237 | \f[I]\f[CI]--lock\f[I]\f[R] 238 | Lock screen. 239 | .SH FILES 240 | .TP 241 | \f[I]\f[CI]\[ti]/.config/powerkit/powerkit.conf\f[I]\f[R] 242 | Per user configuration file. 243 | .SH SEE ALSO 244 | \f[B]\f[CB]xsecurelock\f[B]\f[R](1), \f[B]\f[CB]UPower\f[B]\f[R](7), 245 | \f[B]\f[CB]systemd-logind\f[B]\f[R](8) 246 | .SH BUGS 247 | See \f[B]https://github.com/rodlie/powerkit/issues\f[R]. 248 | .SH COPYRIGHT 249 | .IP 250 | .EX 251 | Copyright (c) Ole-André Rodlie 252 | All rights reserved. 253 | 254 | Redistribution and use in source and binary forms, with or without 255 | modification, are permitted provided that the following conditions are met: 256 | 257 | * Redistributions of source code must retain the above copyright notice, this 258 | list of conditions and the following disclaimer. 259 | 260 | * Redistributions in binary form must reproduce the above copyright notice, 261 | this list of conditions and the following disclaimer in the documentation 262 | and/or other materials provided with the distribution. 263 | 264 | * Neither the name of the copyright holder nor the names of its 265 | contributors may be used to endorse or promote products derived from 266 | this software without specific prior written permission. 267 | 268 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \[dq]AS IS\[dq] 269 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 270 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 271 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 272 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 273 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 274 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 275 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 276 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 277 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 278 | .EE 279 | .SH AUTHORS 280 | Ole-André Rodlie. 281 | -------------------------------------------------------------------------------- /docs/powerkit.md: -------------------------------------------------------------------------------- 1 | # NAME 2 | 3 | *powerkit* - Desktop independent power manager for Linux 4 | 5 | # SYNOPSIS 6 | 7 | powerkit *`[--config]`* *`[--set-brightness-up]`* *`[--set-brightness-down]`* *`[--sleep]`* *`[--hibernate]`* *`[--lock]`* 8 | 9 | # DESCRIPTION 10 | 11 | Desktop independent power manager for use with alternative X11 desktop environments and window managers on Linux. 12 | 13 | * Implements *``org.freedesktop.ScreenSaver``* service 14 | * Implements *``org.freedesktop.PowerManagement.Inhibit``* service 15 | * Automatic actions on lid, idle and low battery 16 | * Sleep 17 | * Hibernate 18 | * HybridSleep 19 | * Suspend then Hibernate 20 | * Shutdown 21 | * Screen saver support 22 | * Screen lid support 23 | * Screen locking support 24 | * Screen backlight support 25 | * Notification support (can use *``org.freedesktop.Notifications``* if available) 26 | 27 | # USAGE 28 | 29 | powerkit should be started during the X11 user session. Consult the documentation for your desktop environment or window manager for launching startup applications. 30 | 31 | * In *Fluxbox* add *``powerkit &``* to the *``~/.fluxbox/startup``* file 32 | * In *Openbox* add *``powerkit &``* to the *``~/.config/openbox/autostart``* file. 33 | 34 | **Do use powerkit if your desktop environment or window manager already has a power manager or screen saver service running.** 35 | 36 | ## CONFIGURATION 37 | 38 | Settings are available directly from the system tray icon or run *``powerkit --config``*. You should also be able to lauch the powerkit settings from your desktop application menu (if available). 39 | 40 | ## SCREEN SAVER 41 | 42 | powerkit implements a basic screen saver to handle screen blanking, poweroff and locking feature. 43 | 44 | Locking feature depends on ``xsecurelock``. 45 | 46 | You can override the lock command with *``screensaver_lock_cmd=``* in *`~/.config/powerkit/powerkit.conf`*. Note that the command must not contain spaces. 47 | 48 | ## BACKLIGHT 49 | 50 | The current display brightness (on laptops and supported displays) can be adjusted with the mouse wheel on the system tray icon or through the system tray menu. 51 | 52 | powerkit also supports the following commands that can be used for global shortcuts, scripts etc: 53 | 54 | *`powerkit --set-brightness-up`* 55 | : Set default display brightness up. 56 | 57 | *`powerkit --set-brightness-down`* 58 | : Set default display brightness down. 59 | 60 | On Fluxbox you can add the commands to the *`~/.fluxbox/keys`* file: 61 | 62 | ``` 63 | XF86MonBrightnessUp :Exec powerkit --set-brightness-up 64 | XF86MonBrightnessDown :Exec powerkit --set-brightness-down 65 | ``` 66 | 67 | ## HIBERNATE 68 | 69 | If hibernate works depends on your system, a swap partition (or file) is needed by the kernel to support hibernate. 70 | 71 | ***Consult your system documentation regarding hibernation***. 72 | 73 | ## ICONS 74 | 75 | powerkit will use the existing icon theme from the running desktop environment or window manager. 76 | 77 | You can override the icon theme in the *`~/.config/powerkit/powerkit.conf`* file, use *``icon_theme=``*. 78 | 79 | # FAQ 80 | 81 | ## How does an application inhibit the screen saver? 82 | 83 | The preferred way to inhibit the screen saver from an application is to use the *org.freedesktop.ScreenSaver* specification. Any application that uses *org.freedesktop.ScreenSaver* will work with powerkit. 84 | 85 | Popular applications that uses this feature is Mozilla Firefox, Google Chrome, VideoLAN VLC and many more. 86 | 87 | ## How does an application inhibit suspend actions? 88 | 89 | The preferred way to inhibit suspend actions from an application is to use the *org.freedesktop.PowerManagement* specification. Any application that uses *org.freedesktop.PowerManagement* will work with powerkit. 90 | 91 | Common use cases are audio playback, downloading, rendering and similar. 92 | 93 | ## Google Chrome/Chromium does not inhibit the screen saver or power manager!? 94 | 95 | Chrome does not use *org.freedesktop.ScreenSaver* or *org.freedesktop.PowerManagement* until it detects a supported desktop environment. Add the following to *``~/.bashrc``* or the *``google-chrome``* launcher if you don't run a supported desktop environment: 96 | 97 | ``` 98 | export DESKTOP_SESSION=xfce 99 | export XDG_CURRENT_DESKTOP=xfce 100 | ``` 101 | 102 | ## Mozilla Firefox does not inhibit the power manager during audio playback and/or downloading!? 103 | 104 | This is an issue with Firefox (missing feature). Use a different browser or open a request on the Firefox issue tracker. 105 | 106 | Firefox should inhibit the power manager during audio playback (regardless of video) and during download (active queue). Currently Firefox only inhibit the screen saver during video playback. Chrome/Chromium does this correctly. 107 | 108 | # REQUIREMENTS 109 | 110 | powerkit requires the following dependencies: 111 | 112 | * *[X11](https://www.x.org)* 113 | * *[libXss](https://www.x.org/archive//X11R7.7/doc/man/man3/Xss.3.xhtml)* 114 | * *[libXrandr](https://www.x.org/wiki/libraries/libxrandr/)* 115 | * *[Qt](https://qt.io)* 5.15 *(Core/DBus/Gui/Widgets)* 116 | * *[logind](https://www.freedesktop.org/wiki/Software/systemd/logind/)* *(or compatible service)* 117 | * *[UPower](https://upower.freedesktop.org/)* *(or compatible service)* 118 | * *[xsecurelock](https://github.com/google/xsecurelock)* 119 | 120 | # BUILD 121 | 122 | First make sure you have the required dependencies installed, then review the most common build options: 123 | 124 | * *``CMAKE_INSTALL_PREFIX=``* - Install target. *``/usr``* recommended. 125 | * *``CMAKE_BUILD_TYPE=``* - Build type. *``Release``* recommended 126 | 127 | Now configure powerkit with CMake and build: 128 | 129 | ``` 130 | mkdir build && cd build 131 | cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release .. 132 | make -j4 133 | ``` 134 | 135 | All you need is the *``powerkit``* binary located in the build directory, you can run it from any location. 136 | 137 | ## Install 138 | 139 | Use regular *``make install``* with optional *``DESTDIR``*: 140 | 141 | ``` 142 | make DESTDIR= install 143 | ``` 144 | 145 | or make a native package: 146 | 147 | ``` 148 | cpack -G DEB 149 | ``` 150 | ``` 151 | cpack -G RPM 152 | ``` 153 | 154 | # CHANGELOG 155 | 156 | ## 2.0.0 (TBA) 157 | 158 | * Recommended locker is ``xsecurelock`` 159 | * Added support for "modern" logind 160 | * Removed support for ConsoleKit 161 | * Removed support for XScreenSaver 162 | * Added basic screen saver 163 | * Easier to use (minimal/no setup) 164 | * New UI 165 | * Major code changes 166 | 167 | # OPTIONS 168 | 169 | *``--config``* 170 | : Launch configuration. 171 | 172 | *`--set-brightness-up`* 173 | : Set default display brightness up. 174 | 175 | *`--set-brightness-down`* 176 | : Set default display brightness down. 177 | 178 | *`--sleep`* 179 | : Suspend computer now. Can be combined with *`--hibernate`* for suspend then hibernate after X amount of time. 180 | 181 | *`--hibernate`* 182 | : Hibernate computer now. Can be combined with *`--sleep`* for suspend then hibernate after X amount of time. 183 | 184 | *`--lock`* 185 | : Lock screen. 186 | 187 | # FILES 188 | 189 | *``~/.config/powerkit/powerkit.conf``* 190 | : Per user configuration file. 191 | 192 | # SEE ALSO 193 | 194 | **``xsecurelock``**(1), **``UPower``**(7), **``systemd-logind``**(8) 195 | 196 | # BUGS 197 | 198 | See **https://github.com/rodlie/powerkit/issues**. 199 | 200 | # COPYRIGHT 201 | 202 | ``` 203 | Copyright (c) Ole-André Rodlie 204 | All rights reserved. 205 | 206 | Redistribution and use in source and binary forms, with or without 207 | modification, are permitted provided that the following conditions are met: 208 | 209 | * Redistributions of source code must retain the above copyright notice, this 210 | list of conditions and the following disclaimer. 211 | 212 | * Redistributions in binary form must reproduce the above copyright notice, 213 | this list of conditions and the following disclaimer in the documentation 214 | and/or other materials provided with the distribution. 215 | 216 | * Neither the name of the copyright holder nor the names of its 217 | contributors may be used to endorse or promote products derived from 218 | this software without specific prior written permission. 219 | 220 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 221 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 222 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 223 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 224 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 225 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 226 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 227 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 228 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 229 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 230 | ``` 231 | -------------------------------------------------------------------------------- /docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rodlie/powerkit/f179578cfffc433b13cdb204cb27af9b6e35449b/docs/screenshot.png -------------------------------------------------------------------------------- /share/90-backlight.rules: -------------------------------------------------------------------------------- 1 | ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="acpi_video0", RUN+="/bin/chgrp video /sys/class/backlight/%k/brightness" 2 | ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="acpi_video0", RUN+="/bin/chmod g+w /sys/class/backlight/%k/brightness" 3 | ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="intel_backlight", RUN+="/bin/chgrp video /sys/class/backlight/%k/brightness" 4 | ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="intel_backlight", RUN+="/bin/chmod g+w /sys/class/backlight/%k/brightness" 5 | ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="radeon_bl0", RUN+="/bin/chgrp video /sys/class/backlight/%k/brightness" 6 | ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="radeon_bl0", RUN+="/bin/chmod g+w /sys/class/backlight/%k/brightness" 7 | ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="amdgpu_bl0", RUN+="/bin/chgrp video /sys/class/backlight/%k/brightness" 8 | ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="amdgpu_bl0", RUN+="/bin/chmod g+w /sys/class/backlight/%k/brightness" 9 | -------------------------------------------------------------------------------- /share/com.ubuntu.enable-hibernate.pkla: -------------------------------------------------------------------------------- 1 | [Re-enable hibernate by default in upower] 2 | Identity=unix-user:* 3 | Action=org.freedesktop.upower.hibernate 4 | ResultActive=yes 5 | 6 | [Re-enable hibernate by default in logind] 7 | Identity=unix-user:* 8 | Action=org.freedesktop.login1.hibernate;org.freedesktop.login1.handle-hibernate-key;org.freedesktop.login1;org.freedesktop.login1.hibernate-multiple-sessions;org.freedesktop.login1.hibernate-ignore-inhibit 9 | ResultActive=yes 10 | 11 | -------------------------------------------------------------------------------- /share/org.freedesktop.PowerManagement.Inhibit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /share/org.freedesktop.ScreenSaver.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /share/powerkit.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=PowerKit 3 | Comment=Power Manager 4 | Icon=ac-adapter 5 | Exec=@PROJECT_NAME@ --config 6 | Terminal=false 7 | Type=Application 8 | Categories=Settings; 9 | StartupNotify=false 10 | -------------------------------------------------------------------------------- /src/powerkit.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include 10 | 11 | #include "powerkit_app.h" 12 | #include "powerkit_dialog.h" 13 | #include "powerkit_common.h" 14 | #include "powerkit_backlight.h" 15 | #include "powerkit_client.h" 16 | 17 | #define CMD_OPT_CONFIG "--config" 18 | #define CMD_OPT_BRIGHTNESS_UP "--set-brightness-up" 19 | #define CMD_OPT_BRIGHTNESS_DOWN "--set-brightness-down" 20 | #define CMD_OPT_SLEEP "--sleep" 21 | #define CMD_OPT_HIBERNATE "--hibernate" 22 | #define CMD_OPT_LOCK "--lock" 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | QApplication a(argc, argv); 27 | QCoreApplication::setApplicationName("freedesktop"); 28 | QCoreApplication::setOrganizationDomain("org"); 29 | QCoreApplication::setApplicationVersion(QString::fromUtf8(POWERKIT_VERSION)); 30 | 31 | const auto args = QApplication::arguments(); 32 | bool openConfig = args.contains(CMD_OPT_CONFIG); 33 | bool setBrightness = (args.contains(CMD_OPT_BRIGHTNESS_UP) || 34 | args.contains(CMD_OPT_BRIGHTNESS_DOWN)); 35 | bool setSleep = args.contains(CMD_OPT_SLEEP); 36 | bool setHibernate = args.contains(CMD_OPT_HIBERNATE); 37 | bool setLock = args.contains(CMD_OPT_LOCK); 38 | 39 | if (openConfig) { 40 | if (!QDBusConnection::sessionBus().registerService(POWERKIT_CONFIG)) { 41 | qWarning() << QObject::tr("A powerkit config instance is already running"); 42 | return 1; 43 | } 44 | PowerKit::Dialog dialog; 45 | dialog.show(); 46 | return a.exec(); 47 | } else if (setBrightness) { 48 | int val = PowerKit::Backlight::getCurrentBrightness(); 49 | if (args.contains(CMD_OPT_BRIGHTNESS_UP)) { val += POWERKIT_BACKLIGHT_STEP; } 50 | else if (args.contains(CMD_OPT_BRIGHTNESS_DOWN)) { val -= POWERKIT_BACKLIGHT_STEP; } 51 | return PowerKit::Backlight::setBrightness(val); 52 | } else if (setSleep || setHibernate || setLock) { 53 | QDBusInterface manager(POWERKIT_SERVICE, 54 | POWERKIT_PATH, 55 | POWERKIT_MANAGER, 56 | QDBusConnection::sessionBus()); 57 | if (!manager.isValid()) { 58 | qWarning() << QObject::tr("Unable to connect to the powerkit service"); 59 | return 1; 60 | } 61 | if (setSleep && setHibernate) { 62 | return PowerKit::Client::suspendThenHibernate(&manager); 63 | } else if (setSleep) { 64 | return PowerKit::Client::suspend(&manager); 65 | } else if (setHibernate) { 66 | return PowerKit::Client::hibernate(&manager); 67 | } else if (setLock) { 68 | return PowerKit::Client::lockScreen(&manager); 69 | } 70 | return 1; 71 | } 72 | 73 | QDBusInterface session(POWERKIT_SERVICE, 74 | POWERKIT_PATH, 75 | POWERKIT_SERVICE, 76 | QDBusConnection::sessionBus()); 77 | if (session.isValid()) { 78 | qWarning() << QObject::tr("A powerkit session is already running"); 79 | return 1; 80 | } 81 | 82 | PowerKit::App powerkit(a.parent()); 83 | return a.exec(); 84 | } 85 | -------------------------------------------------------------------------------- /src/powerkit_app.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include "powerkit_app.h" 10 | #include "powerkit_common.h" 11 | #include "powerkit_theme.h" 12 | #include "powerkit_notify.h" 13 | #include "powerkit_settings.h" 14 | #include "powerkit_backlight.h" 15 | 16 | #include "InhibitAdaptor.h" 17 | #include "ScreenSaverAdaptor.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define VIRTUAL_MONITOR "VIRTUAL" 27 | 28 | #define PK_SCREENSAVER_SERVICE "org.freedesktop.ScreenSaver" 29 | #define PK_SCREENSAVER_PATH_ROOT "/ScreenSaver" 30 | #define PK_SCREENSAVER_PATH_FULL "/org/freedesktop/ScreenSaver" 31 | 32 | #define PM_SERVICE_INHIBIT "org.freedesktop.PowerManagement.Inhibit" 33 | #define PM_FULL_PATH_INHIBIT "/org/freedesktop/PowerManagement/Inhibit" 34 | 35 | #define PM_SERVICE "org.freedesktop.PowerManagement" 36 | #define PM_FULL_PATH "/org/freedesktop/PowerManagement" 37 | #define POWERKIT_FULL_PATH "/org/freedesktop/PowerKit" 38 | 39 | using namespace PowerKit; 40 | 41 | App::App(QObject *parent) 42 | : QObject(parent) 43 | , tray(nullptr) 44 | , man(nullptr) 45 | , pm(nullptr) 46 | , ss(nullptr) 47 | , wasLowBattery(false) 48 | , wasVeryLowBattery(false) 49 | , lowBatteryValue(POWERKIT_LOW_BATTERY) 50 | , critBatteryValue(POWERKIT_CRITICAL_BATTERY) 51 | , hasService(false) 52 | , lidActionBattery(POWERKIT_LID_BATTERY_ACTION) 53 | , lidActionAC(POWERKIT_LID_AC_ACTION) 54 | , criticalAction(POWERKIT_CRITICAL_ACTION) 55 | , autoSuspendBattery(POWERKIT_AUTO_SLEEP_BATTERY) 56 | , autoSuspendAC(0) 57 | , timer(nullptr) 58 | , timeouts(0) 59 | , showNotifications(true) 60 | , showTray(true) 61 | , disableLidOnExternalMonitors(false) 62 | , autoSuspendBatteryAction(POWERKIT_SUSPEND_BATTERY_ACTION) 63 | , autoSuspendACAction(POWERKIT_SUSPEND_AC_ACTION) 64 | , watcher(nullptr) 65 | , lidXrandr(false) 66 | , lidWasClosed(false) 67 | , hasBacklight(false) 68 | , backlightOnBattery(false) 69 | , backlightOnAC(false) 70 | , backlightBatteryValue(0) 71 | , backlightACValue(0) 72 | , backlightBatteryDisableIfLower(false) 73 | , backlightACDisableIfHigher(false) 74 | , warnOnLowBattery(true) 75 | , warnOnVeryLowBattery(true) 76 | , notifyOnBattery(true) 77 | , notifyOnAC(true) 78 | , notifyNewInhibitor(true) 79 | , backlightMouseWheel(true) 80 | , ignoreKernelResume(false) 81 | { 82 | // setup tray 83 | tray = new TrayIcon(this); 84 | connect(tray, 85 | SIGNAL(activated(QSystemTrayIcon::ActivationReason)), 86 | this, 87 | SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); 88 | connect(tray, 89 | SIGNAL(wheel(TrayIcon::WheelAction)), 90 | this, 91 | SLOT(handleTrayWheel(TrayIcon::WheelAction))); 92 | 93 | // setup org.freedesktop.PowerKit.Manager 94 | man = new Manager(this); 95 | connect(man, 96 | SIGNAL(UpdatedDevices()), 97 | this, 98 | SLOT(checkDevices())); 99 | connect(man, 100 | SIGNAL(LidClosed()), 101 | this, 102 | SLOT(handleClosedLid())); 103 | connect(man, 104 | SIGNAL(LidOpened()), 105 | this, 106 | SLOT(handleOpenedLid())); 107 | connect(man, 108 | SIGNAL(SwitchedToBattery()), 109 | this, 110 | SLOT(handleOnBattery())); 111 | connect(man, 112 | SIGNAL(SwitchedToAC()), 113 | this, 114 | SLOT(handleOnAC())); 115 | connect(man, 116 | SIGNAL(PrepareForSuspend()), 117 | this, 118 | SLOT(handlePrepareForSuspend())); 119 | connect(man, 120 | SIGNAL(PrepareForResume()), 121 | this, 122 | SLOT(handlePrepareForResume())); 123 | connect(man, 124 | SIGNAL(DeviceWasAdded(QString)), 125 | this, 126 | SLOT(handleDeviceChanged(QString))); 127 | connect(man, 128 | SIGNAL(DeviceWasRemoved(QString)), 129 | this, 130 | SLOT(handleDeviceChanged(QString))); 131 | connect(man, 132 | SIGNAL(Update()), 133 | this, 134 | SLOT(loadSettings())); 135 | connect(man, 136 | SIGNAL(Error(QString)), 137 | this, 138 | SLOT(handleError(QString))); 139 | connect(man, 140 | SIGNAL(Warning(QString)), 141 | this, 142 | SLOT(handleWarning(QString))); 143 | 144 | // setup org.freedesktop.PowerManagement 145 | pm = new PowerManagement(this); 146 | connect(pm, 147 | SIGNAL(HasInhibitChanged(bool)), 148 | this, 149 | SLOT(handleHasInhibitChanged(bool))); 150 | connect(pm, 151 | SIGNAL(newInhibit(QString,QString,quint32)), 152 | this, 153 | SLOT(handleNewInhibitPowerManagement(QString,QString,quint32))); 154 | connect(pm, 155 | SIGNAL(removedInhibit(quint32)), 156 | this, 157 | SLOT(handleDelInhibitPowerManagement(quint32))); 158 | connect(pm, 159 | SIGNAL(newInhibit(QString,QString,quint32)), 160 | man, 161 | SLOT(handleNewInhibitPowerManagement(QString,QString,quint32))); 162 | connect(pm, 163 | SIGNAL(removedInhibit(quint32)), 164 | man, 165 | SLOT(handleDelInhibitPowerManagement(quint32))); 166 | 167 | // setup org.freedesktop.ScreenSaver 168 | ss = new ScreenSaver(this); 169 | connect(ss, 170 | SIGNAL(newInhibit(QString,QString,quint32)), 171 | this, 172 | SLOT(handleNewInhibitScreenSaver(QString,QString,quint32))); 173 | connect(ss, 174 | SIGNAL(removedInhibit(quint32)), 175 | this, 176 | SLOT(handleDelInhibitScreenSaver(quint32))); 177 | connect(ss, 178 | SIGNAL(newInhibit(QString,QString,quint32)), 179 | man, 180 | SLOT(handleNewInhibitScreenSaver(QString,QString,quint32))); 181 | connect(ss, 182 | SIGNAL(removedInhibit(quint32)), 183 | man, 184 | SLOT(handleDelInhibitScreenSaver(quint32))); 185 | 186 | // setup timer 187 | timer = new QTimer(this); 188 | timer->setInterval(60000); 189 | connect(timer, 190 | SIGNAL(timeout()), 191 | this, 192 | SLOT(timeout())); 193 | timer->start(); 194 | 195 | // check for config 196 | Settings::getConf(); 197 | 198 | // setup theme 199 | Theme::setAppTheme(); 200 | Theme::setIconTheme(); 201 | if (tray->icon().isNull()) { 202 | tray->setIcon(QIcon::fromTheme(POWERKIT_ICON)); 203 | } 204 | 205 | loadSettings(); 206 | registerService(); 207 | 208 | // device check 209 | QTimer::singleShot(10000, 210 | this, 211 | SLOT(checkDevices())); 212 | QTimer::singleShot(1000, 213 | this, 214 | SLOT(setInternalMonitor())); 215 | 216 | // setup watcher 217 | watcher = new QFileSystemWatcher(this); 218 | watcher->addPath(Settings::getDir()); 219 | watcher->addPath(Settings::getConf()); 220 | connect(watcher, 221 | SIGNAL(fileChanged(QString)), 222 | this, 223 | SLOT(handleConfChanged(QString))); 224 | connect(watcher, 225 | SIGNAL(directoryChanged(QString)), 226 | this, 227 | SLOT(handleConfChanged(QString))); 228 | } 229 | 230 | App::~App() 231 | { 232 | } 233 | 234 | void App::trayActivated(QSystemTrayIcon::ActivationReason reason) 235 | { 236 | Q_UNUSED(reason) 237 | 238 | openSettings(); 239 | } 240 | 241 | void App::checkDevices() 242 | { 243 | updateTrayVisibility(); 244 | 245 | double batteryLeft = man->BatteryLeft(); 246 | qDebug() << "battery at" << batteryLeft; 247 | 248 | drawBattery(batteryLeft); 249 | updateToolTip(); 250 | 251 | handleLow(batteryLeft); 252 | handleVeryLow(batteryLeft); 253 | handleCritical(batteryLeft); 254 | } 255 | 256 | void App::handleClosedLid() 257 | { 258 | qDebug() << "lid closed"; 259 | lidWasClosed = true; 260 | 261 | int type = lidNone; 262 | if (man->OnBattery()) { 263 | type = lidActionBattery; 264 | } else { // on ac 265 | type = lidActionAC; 266 | } 267 | 268 | if (disableLidOnExternalMonitors && 269 | externalMonitorIsConnected()) { 270 | qDebug() << "external monitor is connected, ignore lid action"; 271 | switchInternalMonitor(false /* turn off screen */); 272 | return; 273 | } 274 | 275 | qDebug() << "lid action" << type; 276 | switch(type) { 277 | case lidLock: 278 | man->LockScreen(); 279 | break; 280 | case lidSleep: 281 | man->Suspend(); 282 | break; 283 | case lidHibernate: 284 | man->Hibernate(); 285 | break; 286 | case lidShutdown: 287 | man->PowerOff(); 288 | break; 289 | case lidHybridSleep: 290 | man->HybridSleep(); 291 | break; 292 | case lidSleepHibernate: 293 | man->SuspendThenHibernate(); 294 | break; 295 | default:; 296 | } 297 | } 298 | 299 | void App::handleOpenedLid() 300 | { 301 | qDebug() << "lid is now open"; 302 | lidWasClosed = false; 303 | if (disableLidOnExternalMonitors) { 304 | switchInternalMonitor(true /* turn on screen */); 305 | } 306 | } 307 | 308 | void App::handleOnBattery() 309 | { 310 | if (notifyOnBattery) { 311 | showMessage(tr("On Battery"), 312 | tr("Switched to battery power.")); 313 | } 314 | 315 | // brightness 316 | if (backlightOnBattery && backlightBatteryValue > 0) { 317 | qDebug() << "set brightness on battery"; 318 | if (backlightBatteryDisableIfLower && 319 | backlightBatteryValue > Backlight::getCurrentBrightness(backlightDevice)) { 320 | qDebug() << "brightness is lower than battery value, ignore"; 321 | return; 322 | } 323 | Backlight::setBrightness(backlightDevice, 324 | backlightBatteryValue); 325 | } 326 | } 327 | 328 | void App::handleOnAC() 329 | { 330 | if (notifyOnAC) { 331 | showMessage(tr("On AC"), 332 | tr("Switched to AC power.")); 333 | } 334 | 335 | wasLowBattery = false; 336 | wasVeryLowBattery = false; 337 | 338 | // brightness 339 | if (backlightOnAC && backlightACValue > 0) { 340 | qDebug() << "set brightness on ac"; 341 | if (backlightACDisableIfHigher && 342 | backlightACValue < Backlight::getCurrentBrightness(backlightDevice)) { 343 | qDebug() << "brightness is higher than ac value, ignore"; 344 | return; 345 | } 346 | Backlight::setBrightness(backlightDevice, 347 | backlightACValue); 348 | } 349 | } 350 | 351 | void App::loadSettings() 352 | { 353 | qDebug() << "(re)load settings..."; 354 | 355 | // set default settings 356 | if (Settings::isValid(CONF_SUSPEND_BATTERY_TIMEOUT)) { 357 | autoSuspendBattery = Settings::getValue(CONF_SUSPEND_BATTERY_TIMEOUT).toInt(); 358 | } 359 | if (Settings::isValid(CONF_SUSPEND_AC_TIMEOUT)) { 360 | autoSuspendAC = Settings::getValue(CONF_SUSPEND_AC_TIMEOUT).toInt(); 361 | } 362 | if (Settings::isValid(CONF_SUSPEND_BATTERY_ACTION)) { 363 | autoSuspendBatteryAction = Settings::getValue(CONF_SUSPEND_BATTERY_ACTION).toInt(); 364 | } 365 | if (Settings::isValid(CONF_SUSPEND_AC_ACTION)) { 366 | autoSuspendACAction = Settings::getValue(CONF_SUSPEND_AC_ACTION).toInt(); 367 | } 368 | if (Settings::isValid(CONF_CRITICAL_BATTERY_TIMEOUT)) { 369 | critBatteryValue = Settings::getValue(CONF_CRITICAL_BATTERY_TIMEOUT).toInt(); 370 | } 371 | if (Settings::isValid(CONF_LID_BATTERY_ACTION)) { 372 | lidActionBattery = Settings::getValue(CONF_LID_BATTERY_ACTION).toInt(); 373 | } 374 | if (Settings::isValid(CONF_LID_AC_ACTION)) { 375 | lidActionAC = Settings::getValue(CONF_LID_AC_ACTION).toInt(); 376 | } 377 | if (Settings::isValid(CONF_CRITICAL_BATTERY_ACTION)) { 378 | criticalAction = Settings::getValue(CONF_CRITICAL_BATTERY_ACTION).toInt(); 379 | } 380 | if (Settings::isValid(CONF_TRAY_NOTIFY)) { 381 | showNotifications = Settings::getValue(CONF_TRAY_NOTIFY).toBool(); 382 | } 383 | if (Settings::isValid(CONF_TRAY_SHOW)) { 384 | showTray = Settings::getValue(CONF_TRAY_SHOW).toBool(); 385 | } 386 | if (Settings::isValid(CONF_LID_DISABLE_IF_EXTERNAL)) { 387 | disableLidOnExternalMonitors = Settings::getValue(CONF_LID_DISABLE_IF_EXTERNAL).toBool(); 388 | } 389 | if (Settings::isValid(CONF_LID_XRANDR)) { 390 | lidXrandr = Settings::getValue(CONF_LID_XRANDR).toBool(); 391 | } 392 | if (Settings::isValid(CONF_BACKLIGHT_AC_ENABLE)) { 393 | backlightOnAC = Settings::getValue(CONF_BACKLIGHT_AC_ENABLE).toBool(); 394 | } 395 | if (Settings::isValid(CONF_BACKLIGHT_AC)) { 396 | backlightACValue = Settings::getValue(CONF_BACKLIGHT_AC).toInt(); 397 | } 398 | if (Settings::isValid(CONF_BACKLIGHT_BATTERY_ENABLE)) { 399 | backlightOnBattery = Settings::getValue(CONF_BACKLIGHT_BATTERY_ENABLE).toBool(); 400 | } 401 | if (Settings::isValid(CONF_BACKLIGHT_BATTERY)) { 402 | backlightBatteryValue = Settings::getValue(CONF_BACKLIGHT_BATTERY).toInt(); 403 | } 404 | if (Settings::isValid(CONF_BACKLIGHT_BATTERY_DISABLE_IF_LOWER)) { 405 | backlightBatteryDisableIfLower = Settings::getValue(CONF_BACKLIGHT_BATTERY_DISABLE_IF_LOWER) 406 | .toBool(); 407 | } 408 | if (Settings::isValid(CONF_BACKLIGHT_AC_DISABLE_IF_HIGHER)) { 409 | backlightACDisableIfHigher = Settings::getValue(CONF_BACKLIGHT_AC_DISABLE_IF_HIGHER) 410 | .toBool(); 411 | } 412 | if (Settings::isValid(CONF_WARN_ON_LOW_BATTERY)) { 413 | warnOnLowBattery = Settings::getValue(CONF_WARN_ON_LOW_BATTERY).toBool(); 414 | } 415 | if (Settings::isValid(CONF_WARN_ON_VERYLOW_BATTERY)) { 416 | warnOnVeryLowBattery = Settings::getValue(CONF_WARN_ON_VERYLOW_BATTERY).toBool(); 417 | } 418 | if (Settings::isValid(CONF_NOTIFY_ON_BATTERY)) { 419 | notifyOnBattery = Settings::getValue(CONF_NOTIFY_ON_BATTERY).toBool(); 420 | } 421 | if (Settings::isValid(CONF_NOTIFY_ON_AC)) { 422 | notifyOnAC = Settings::getValue(CONF_NOTIFY_ON_AC).toBool(); 423 | } 424 | if (Settings::isValid(CONF_NOTIFY_NEW_INHIBITOR)) { 425 | notifyNewInhibitor = Settings::getValue(CONF_NOTIFY_NEW_INHIBITOR).toBool(); 426 | } 427 | /*if (Settings::isValid(CONF_SUSPEND_WAKEUP_HIBERNATE_BATTERY)) { 428 | man->SetSuspendWakeAlarmOnBattery(Settings::getValue(CONF_SUSPEND_WAKEUP_HIBERNATE_BATTERY).toInt()); 429 | } 430 | if (Settings::isValid(CONF_SUSPEND_WAKEUP_HIBERNATE_AC)) { 431 | man->SetSuspendWakeAlarmOnAC(Settings::getValue(CONF_SUSPEND_WAKEUP_HIBERNATE_AC).toInt()); 432 | }*/ 433 | 434 | if (Settings::isValid(CONF_KERNEL_BYPASS)) { 435 | ignoreKernelResume = Settings::getValue(CONF_KERNEL_BYPASS).toBool(); 436 | } else { 437 | ignoreKernelResume = false; 438 | } 439 | 440 | // verify 441 | /*if (!Common::kernelCanResume(ignoreKernelResume)) { 442 | qDebug() << "hibernate is not activated in kernel (add resume=...)"; 443 | disableHibernate(); 444 | }*/ 445 | if (!man->CanHibernate()) { 446 | qWarning() << "hibernate is not supported"; 447 | disableHibernate(); 448 | } 449 | if (!man->CanSuspend()) { 450 | qWarning() << "suspend not supported"; 451 | disableSuspend(); 452 | } 453 | 454 | // backlight 455 | backlightDevice = Backlight::getDevice(); 456 | hasBacklight = Backlight::canAdjustBrightness(backlightDevice); 457 | if (Settings::isValid(CONF_BACKLIGHT_MOUSE_WHEEL)) { 458 | backlightMouseWheel = Settings::getValue(CONF_BACKLIGHT_MOUSE_WHEEL).toBool(); 459 | } 460 | 461 | // screensaver 462 | ss->Update(); 463 | } 464 | 465 | void App::registerService() 466 | { 467 | if (hasService) { return; } 468 | if (!QDBusConnection::sessionBus().isConnected()) { 469 | qWarning() << tr("Cannot connect to D-Bus."); 470 | return; 471 | } 472 | hasService = true; 473 | 474 | // register org.freedesktop.PowerManagement 475 | bool hasDesktopPM = true; 476 | if (!QDBusConnection::sessionBus().registerService(PM_SERVICE)) { 477 | qWarning() << QDBusConnection::sessionBus().lastError().message(); 478 | hasDesktopPM = false; 479 | } else { 480 | if (!QDBusConnection::sessionBus().registerService(PM_SERVICE_INHIBIT)) { 481 | qWarning() << QDBusConnection::sessionBus().lastError().message(); 482 | hasDesktopPM = false; 483 | } else { 484 | new InhibitAdaptor(pm); 485 | if (!QDBusConnection::sessionBus().registerObject(PM_FULL_PATH_INHIBIT, pm)) { 486 | qWarning() << QDBusConnection::sessionBus().lastError().message(); 487 | hasDesktopPM = false; 488 | } 489 | } 490 | } 491 | qWarning() << "Enabled org.freedesktop.PowerManagement" << hasDesktopPM; 492 | 493 | // register org.freedesktop.ScreenSaver 494 | bool hasScreenSaver = true; 495 | if (!QDBusConnection::sessionBus().registerService(PK_SCREENSAVER_SERVICE)) { 496 | qWarning() << "Failed to register screensaver service" << QDBusConnection::sessionBus().lastError().message(); 497 | hasScreenSaver = false; 498 | } else { 499 | new ScreenSaverAdaptor(ss); 500 | if (!QDBusConnection::sessionBus().registerObject(PK_SCREENSAVER_PATH_ROOT, ss)) { 501 | qWarning() << "Failed to register screensaver object" << QDBusConnection::sessionBus().lastError().message(); 502 | hasScreenSaver = false; 503 | } 504 | if (!QDBusConnection::sessionBus().registerObject(PK_SCREENSAVER_PATH_FULL, ss)) { 505 | qWarning() << "Failed to register screensaver object" << QDBusConnection::sessionBus().lastError().message(); 506 | hasScreenSaver = false; 507 | } 508 | } 509 | qWarning() << "Enabled org.freedesktop.ScreenSaver" << hasScreenSaver; 510 | 511 | bool hasDesktopPK = true; 512 | if (!QDBusConnection::sessionBus().registerService(POWERKIT_SERVICE)) { 513 | qWarning() << QDBusConnection::sessionBus().lastError().message(); 514 | hasDesktopPK = false; 515 | } 516 | if (!QDBusConnection::sessionBus().registerObject(POWERKIT_PATH, 517 | man, 518 | QDBusConnection::ExportAllContents)) { 519 | qWarning() << QDBusConnection::sessionBus().lastError().message(); 520 | hasDesktopPK = false; 521 | } 522 | if (!QDBusConnection::sessionBus().registerObject(POWERKIT_FULL_PATH, 523 | man, 524 | QDBusConnection::ExportAllContents)) { 525 | qWarning() << QDBusConnection::sessionBus().lastError().message(); 526 | hasDesktopPK = false; 527 | } 528 | qWarning() << "Enabled org.freedesktop.PowerKit" << hasDesktopPK; 529 | 530 | if (!hasDesktopPK || !hasDesktopPM || !hasScreenSaver) { hasService = false; } 531 | 532 | if (!hasService) { handleError(tr("Failed to setup and/or connect required services!")); } 533 | } 534 | 535 | // dbus session inhibit status handler 536 | void App::handleHasInhibitChanged(bool has_inhibit) 537 | { 538 | if (has_inhibit) { resetTimer(); } 539 | } 540 | 541 | void App::handleLow(double left) 542 | { 543 | if (!warnOnLowBattery) { return; } 544 | double batteryLow = (double)(lowBatteryValue+critBatteryValue); 545 | if (left<=batteryLow && man->OnBattery()) { 546 | if (!wasLowBattery) { 547 | showMessage(QString("%1 (%2%)").arg(tr("Low Battery!")).arg(left), 548 | tr("The battery is low," 549 | " please consider connecting" 550 | " your computer to a power supply."), 551 | true); 552 | wasLowBattery = true; 553 | } 554 | } 555 | } 556 | 557 | void App::handleVeryLow(double left) 558 | { 559 | if (!warnOnVeryLowBattery) { return; } 560 | double batteryVeryLow = (double)(critBatteryValue+1); 561 | if (left<=batteryVeryLow && man->OnBattery()) { 562 | if (!wasVeryLowBattery) { 563 | showMessage(QString("%1 (%2%)").arg(tr("Very Low Battery!")).arg(left), 564 | tr("The battery is almost empty," 565 | " please connect" 566 | " your computer to a power supply now."), 567 | true); 568 | wasVeryLowBattery = true; 569 | } 570 | } 571 | } 572 | 573 | void App::handleCritical(double left) 574 | { 575 | if (left<=0 || 576 | left>(double)critBatteryValue || 577 | !man->OnBattery()) { return; } 578 | qDebug() << "critical battery!" << criticalAction << left; 579 | switch(criticalAction) { 580 | case criticalHibernate: 581 | man->Hibernate(); 582 | break; 583 | case criticalShutdown: 584 | man->PowerOff(); 585 | break; 586 | case criticalSuspend: 587 | man->Suspend(); 588 | break; 589 | default: ; 590 | } 591 | } 592 | 593 | void App::drawBattery(double left) 594 | { 595 | if (!showTray && 596 | tray->isVisible()) { 597 | tray->hide(); 598 | return; 599 | } 600 | if (tray->isSystemTrayAvailable() && 601 | !tray->isVisible() && 602 | showTray) { tray->show(); } 603 | 604 | QColor colorBg = Qt::green; 605 | QColor colorFg = Qt::white; 606 | int pixelSize = 22; 607 | if (man->OnBattery()) { 608 | if (left >= 26) { 609 | colorBg = QColor("orange"); 610 | } else { 611 | colorBg = Qt::red; 612 | } 613 | } else { 614 | if (!man->HasBattery()) { left = 100; } 615 | else if (left == 100) { colorFg = Qt::green; } 616 | } 617 | 618 | tray->setIcon(Theme::drawCircleProgress(left, 619 | pixelSize, 620 | 4, 621 | 4, 622 | false, 623 | QString(), 624 | colorBg, 625 | colorFg)); 626 | } 627 | 628 | void App::updateToolTip() 629 | { 630 | if (!tray->isSystemTrayAvailable() || !tray->isVisible()) { return; } 631 | double batteryLeft = man->BatteryLeft(); 632 | if (batteryLeft > 0 && man->HasBattery()) { 633 | tray->setToolTip(QString("%1 %2%").arg(tr("Battery at")).arg(batteryLeft)); 634 | if (man->TimeToEmpty()>0 && man->OnBattery()) { 635 | tray->setToolTip(tray->toolTip() 636 | .append(QString(", %1 %2") 637 | .arg(QDateTime::fromTime_t((uint)man->TimeToEmpty()) 638 | .toUTC().toString("hh:mm"))) 639 | .arg(tr("left"))); 640 | } 641 | if (batteryLeft > 99) { tray->setToolTip(tr("Charged")); } 642 | if (!man->OnBattery() && 643 | man->BatteryLeft() <= 99) { 644 | if (man->TimeToFull()>0) { 645 | tray->setToolTip(tray->toolTip() 646 | .append(QString(", %1 %2") 647 | .arg(QDateTime::fromTime_t((uint)man->TimeToFull()) 648 | .toUTC().toString("hh:mm"))) 649 | .arg(tr("left"))); 650 | } 651 | tray->setToolTip(tray->toolTip().append(QString(" (%1)").arg(tr("Charging")))); 652 | } 653 | } else { tray->setToolTip(tr("On AC")); } 654 | } 655 | 656 | void App::updateTrayVisibility() 657 | { 658 | if (!showTray && 659 | tray->isVisible()) { tray->hide(); } 660 | if (tray->isSystemTrayAvailable() && 661 | !tray->isVisible() && 662 | showTray) { tray->show(); } 663 | } 664 | 665 | // timeout, check if idle 666 | // timeouts and xss must be >= user value and service has to be empty before suspend 667 | void App::timeout() 668 | { 669 | updateTrayVisibility(); 670 | 671 | int uIdle = ss->GetSessionIdleTime() / 60; 672 | 673 | qDebug() << "timeout?" << timeouts << "idle?" << uIdle << "inhibit?" << pm->HasInhibit() << man->GetInhibitors(); 674 | 675 | int autoSuspend = 0; 676 | int autoSuspendAction = suspendNone; 677 | if (man->OnBattery()) { 678 | autoSuspend = autoSuspendBattery; 679 | autoSuspendAction = autoSuspendBatteryAction; 680 | } 681 | else { 682 | autoSuspend = autoSuspendAC; 683 | autoSuspendAction = autoSuspendACAction; 684 | } 685 | 686 | bool doSuspend = false; 687 | if (autoSuspend>0 && 688 | timeouts>=autoSuspend && 689 | uIdle>=autoSuspend && 690 | !pm->HasInhibit()) { doSuspend = true; } 691 | if (!doSuspend) { timeouts++; } 692 | else { 693 | timeouts = 0; 694 | qDebug() << "auto suspend activated" << autoSuspendAction; 695 | switch (autoSuspendAction) { 696 | case suspendSleep: 697 | man->Suspend(); 698 | break; 699 | case suspendHibernate: 700 | man->Hibernate(); 701 | break; 702 | case suspendShutdown: 703 | man->PowerOff(); 704 | break; 705 | case suspendHybrid: 706 | man->HybridSleep(); 707 | break; 708 | case suspendSleepHibernate: 709 | man->SuspendThenHibernate(); 710 | break; 711 | default:; 712 | } 713 | } 714 | } 715 | 716 | void App::resetTimer() 717 | { 718 | timeouts = 0; 719 | } 720 | 721 | void App::setInternalMonitor() 722 | { 723 | internalMonitor = ss->GetInternalDisplay(); 724 | qDebug() << "internal monitor set to" << internalMonitor; 725 | qDebug() << ss->GetDisplays(); 726 | } 727 | 728 | bool App::internalMonitorIsConnected() 729 | { 730 | QMapIterator i(ss->GetDisplays()); 731 | while (i.hasNext()) { 732 | i.next(); 733 | if (i.key() == internalMonitor) { 734 | qDebug() << "internal monitor connected?" << i.key() << i.value(); 735 | return i.value(); 736 | } 737 | } 738 | return false; 739 | } 740 | 741 | bool App::externalMonitorIsConnected() 742 | { 743 | QMapIterator i(ss->GetDisplays()); 744 | while (i.hasNext()) { 745 | i.next(); 746 | if (i.key()!=internalMonitor && 747 | !i.key().startsWith(VIRTUAL_MONITOR)) { 748 | qDebug() << "external monitor connected?" << i.key() << i.value(); 749 | if (i.value()) { return true; } 750 | } 751 | } 752 | return false; 753 | } 754 | 755 | void App::handleNewInhibitScreenSaver(const QString &application, 756 | const QString &reason, 757 | quint32 cookie) 758 | { 759 | Q_UNUSED(cookie) 760 | if (notifyNewInhibitor) { 761 | showMessage(tr("New screen inhibitor"), 762 | QString("%1: %2").arg(application, reason)); 763 | } 764 | 765 | checkDevices(); 766 | } 767 | 768 | void App::handleNewInhibitPowerManagement(const QString &application, 769 | const QString &reason, 770 | quint32 cookie) 771 | { 772 | Q_UNUSED(cookie) 773 | if (notifyNewInhibitor) { 774 | showMessage(tr("New power inhibitor"), 775 | QString("%1: %2").arg(application, reason)); 776 | } 777 | 778 | checkDevices(); 779 | } 780 | 781 | void App::handleDelInhibitScreenSaver(quint32 cookie) 782 | { 783 | Q_UNUSED(cookie) 784 | checkDevices(); 785 | } 786 | 787 | void App::handleDelInhibitPowerManagement(quint32 cookie) 788 | { 789 | Q_UNUSED(cookie) 790 | checkDevices(); 791 | } 792 | 793 | void App::showMessage(const QString &title, 794 | const QString &msg, 795 | bool critical) 796 | { 797 | if (!showNotifications) { return; } 798 | SystemNotification notifier; 799 | if (notifier.valid) { 800 | notifier.sendMessage(title, msg, critical); 801 | } else if (tray->isVisible()) { 802 | if (critical) { 803 | tray->showMessage(title, 804 | msg, 805 | QSystemTrayIcon::Critical, 806 | 900000); 807 | } else { 808 | tray->showMessage(title, msg); 809 | } 810 | } 811 | } 812 | 813 | void App::handleConfChanged(const QString &file) 814 | { 815 | Q_UNUSED(file) 816 | loadSettings(); 817 | } 818 | 819 | void App::disableHibernate() 820 | { 821 | if (criticalAction == criticalHibernate) { 822 | qWarning() << "reset critical action to shutdown"; 823 | criticalAction = criticalShutdown; 824 | Settings::setValue(CONF_CRITICAL_BATTERY_ACTION, 825 | criticalAction); 826 | } 827 | if (lidActionBattery == lidHibernate) { 828 | qWarning() << "reset lid battery action to lock"; 829 | lidActionBattery = lidLock; 830 | Settings::setValue(CONF_LID_BATTERY_ACTION, 831 | lidActionBattery); 832 | } 833 | if (lidActionAC == lidHibernate) { 834 | qWarning() << "reset lid ac action to lock"; 835 | lidActionAC = lidLock; 836 | Settings::setValue(CONF_LID_AC_ACTION, 837 | lidActionAC); 838 | } 839 | if (autoSuspendBatteryAction == suspendHibernate) { 840 | qWarning() << "reset auto suspend battery action to none"; 841 | autoSuspendBatteryAction = suspendNone; 842 | Settings::setValue(CONF_SUSPEND_BATTERY_ACTION, 843 | autoSuspendBatteryAction); 844 | } 845 | if (autoSuspendACAction == suspendHibernate) { 846 | qWarning() << "reset auto suspend ac action to none"; 847 | autoSuspendACAction = suspendNone; 848 | Settings::setValue(CONF_SUSPEND_AC_ACTION, 849 | autoSuspendACAction); 850 | } 851 | } 852 | 853 | void App::disableSuspend() 854 | { 855 | if (lidActionBattery == lidSleep) { 856 | qWarning() << "reset lid battery action to lock"; 857 | lidActionBattery = lidLock; 858 | Settings::setValue(CONF_LID_BATTERY_ACTION, 859 | lidActionBattery); 860 | } 861 | if (lidActionAC == lidSleep) { 862 | qWarning() << "reset lid ac action to lock"; 863 | lidActionAC = lidLock; 864 | Settings::setValue(CONF_LID_AC_ACTION, 865 | lidActionAC); 866 | } 867 | if (autoSuspendBatteryAction == suspendSleep) { 868 | qWarning() << "reset auto suspend battery action to none"; 869 | autoSuspendBatteryAction = suspendNone; 870 | Settings::setValue(CONF_SUSPEND_BATTERY_ACTION, 871 | autoSuspendBatteryAction); 872 | } 873 | if (autoSuspendACAction == suspendSleep) { 874 | qWarning() << "reset auto suspend ac action to none"; 875 | autoSuspendACAction = suspendNone; 876 | Settings::setValue(CONF_SUSPEND_AC_ACTION, 877 | autoSuspendACAction); 878 | } 879 | } 880 | 881 | void App::handlePrepareForSuspend() 882 | { 883 | /*qDebug() << "prepare for suspend"; 884 | resetTimer(); 885 | man->ReleaseSuspendLock();*/ 886 | qDebug() << "do nothing"; 887 | } 888 | 889 | void App::handlePrepareForResume() 890 | { 891 | qDebug() << "prepare for resume ..."; 892 | resetTimer(); 893 | ss->setDisplaysOff(false); 894 | } 895 | 896 | // turn off/on monitor using xrandr 897 | void App::switchInternalMonitor(bool toggle) 898 | { 899 | if (!lidXrandr) { return; } 900 | qDebug() << "using xrandr to turn on/off internal monitor" << internalMonitor << toggle; 901 | QStringList args; 902 | args << "--output" << internalMonitor << (toggle ? "--auto" : "--off"); 903 | QProcess::startDetached("xrandr", args); 904 | } 905 | 906 | // adjust backlight on wheel event (on systray) 907 | void App::handleTrayWheel(TrayIcon::WheelAction action) 908 | { 909 | if (!backlightMouseWheel) { return; } 910 | switch (action) { 911 | case TrayIcon::WheelUp: 912 | Backlight::setBrightness(backlightDevice, 913 | Backlight::getCurrentBrightness(backlightDevice)+POWERKIT_BACKLIGHT_STEP); 914 | break; 915 | case TrayIcon::WheelDown: 916 | Backlight::setBrightness(backlightDevice, 917 | Backlight::getCurrentBrightness(backlightDevice)-POWERKIT_BACKLIGHT_STEP); 918 | break; 919 | default:; 920 | } 921 | } 922 | 923 | void App::handleDeviceChanged(const QString &path) 924 | { 925 | Q_UNUSED(path) 926 | checkDevices(); 927 | } 928 | 929 | void App::openSettings() 930 | { 931 | QProcess::startDetached(qApp->applicationFilePath(), 932 | QStringList() << "--config"); 933 | } 934 | 935 | void App::handleError(const QString &message) 936 | { 937 | qWarning() << "ERROR:" << message; 938 | showMessage(tr("Error"), message, true); 939 | QTimer::singleShot(5000, qApp, SLOT(quit())); 940 | } 941 | 942 | void App::handleWarning(const QString &message) 943 | { 944 | qWarning() << "WARNING:" << message; 945 | showMessage(tr("Warning"), message, true); 946 | } 947 | 948 | bool TrayIcon::event(QEvent *e) 949 | { 950 | if (e->type() == QEvent::Wheel) { 951 | QWheelEvent *w = (QWheelEvent*)e; 952 | //if (w->orientation() == Qt::Vertical) { 953 | wheel_delta += w->angleDelta().y(); 954 | if (abs(wheel_delta) >= 120) { 955 | emit wheel(wheel_delta > 0 ? TrayIcon::WheelUp : TrayIcon::WheelDown); 956 | wheel_delta = 0; 957 | } 958 | //} 959 | return true; 960 | } 961 | return QSystemTrayIcon::event(e); 962 | } 963 | -------------------------------------------------------------------------------- /src/powerkit_app.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_APP_H 10 | #define POWERKIT_APP_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "powerkit_powermanagement.h" 21 | #include "powerkit_screensaver.h" 22 | #include "powerkit_manager.h" 23 | 24 | namespace PowerKit 25 | { 26 | class TrayIcon : public QSystemTrayIcon 27 | { 28 | Q_OBJECT 29 | public: 30 | enum WheelAction { 31 | WheelUp, 32 | WheelDown 33 | }; 34 | TrayIcon(QObject *parent = 0) 35 | : QSystemTrayIcon(parent), wheel_delta(0) {} 36 | TrayIcon(const QIcon &icon, QObject *parent = 0) 37 | : QSystemTrayIcon(icon, parent), wheel_delta(0) {} 38 | bool event(QEvent *event); 39 | signals: 40 | void wheel(TrayIcon::WheelAction action); 41 | private: 42 | int wheel_delta; 43 | }; 44 | 45 | class App : public QObject 46 | { 47 | Q_OBJECT 48 | 49 | public: 50 | explicit App(QObject *parent = NULL); 51 | ~App(); 52 | 53 | private: 54 | TrayIcon *tray; 55 | PowerKit::Manager *man; 56 | PowerKit::PowerManagement *pm; 57 | PowerKit::ScreenSaver *ss; 58 | bool wasLowBattery; 59 | bool wasVeryLowBattery; 60 | int lowBatteryValue; 61 | int critBatteryValue; 62 | bool hasService; 63 | int lidActionBattery; 64 | int lidActionAC; 65 | int criticalAction; 66 | int autoSuspendBattery; 67 | int autoSuspendAC; 68 | QTimer *timer; 69 | int timeouts; 70 | bool showNotifications; 71 | bool showTray; 72 | bool disableLidOnExternalMonitors; 73 | int autoSuspendBatteryAction; 74 | int autoSuspendACAction; 75 | QString internalMonitor; 76 | QFileSystemWatcher *watcher; 77 | bool lidXrandr; 78 | bool lidWasClosed; 79 | QString backlightDevice; 80 | bool hasBacklight; 81 | bool backlightOnBattery; 82 | bool backlightOnAC; 83 | int backlightBatteryValue; 84 | int backlightACValue; 85 | bool backlightBatteryDisableIfLower; 86 | bool backlightACDisableIfHigher; 87 | bool warnOnLowBattery; 88 | bool warnOnVeryLowBattery; 89 | bool notifyOnBattery; 90 | bool notifyOnAC; 91 | bool notifyNewInhibitor; 92 | bool backlightMouseWheel; 93 | bool ignoreKernelResume; 94 | 95 | private slots: 96 | void trayActivated(QSystemTrayIcon::ActivationReason reason); 97 | void checkDevices(); 98 | void handleClosedLid(); 99 | void handleOpenedLid(); 100 | void handleOnBattery(); 101 | void handleOnAC(); 102 | void loadSettings(); 103 | void registerService(); 104 | void handleHasInhibitChanged(bool has_inhibit); 105 | void handleLow(double left); 106 | void handleVeryLow(double left); 107 | void handleCritical(double left); 108 | void drawBattery(double left); 109 | void updateToolTip(); 110 | void updateTrayVisibility(); 111 | void timeout(); 112 | void resetTimer(); 113 | void setInternalMonitor(); 114 | bool internalMonitorIsConnected(); 115 | bool externalMonitorIsConnected(); 116 | void handleNewInhibitScreenSaver(const QString &application, 117 | const QString &reason, 118 | quint32 cookie); 119 | void handleNewInhibitPowerManagement(const QString &application, 120 | const QString &reason, 121 | quint32 cookie); 122 | void handleDelInhibitScreenSaver(quint32 cookie); 123 | void handleDelInhibitPowerManagement(quint32 cookie); 124 | void showMessage(const QString &title, 125 | const QString &msg, 126 | bool critical = false); 127 | void handleConfChanged(const QString &file); 128 | void disableHibernate(); 129 | void disableSuspend(); 130 | void handlePrepareForSuspend(); 131 | void handlePrepareForResume(); 132 | void switchInternalMonitor(bool toggle); 133 | void handleTrayWheel(TrayIcon::WheelAction action); 134 | void handleDeviceChanged(const QString &path); 135 | void openSettings(); 136 | void handleError(const QString &message); 137 | void handleWarning(const QString &message); 138 | }; 139 | } 140 | 141 | #endif // POWERKIT_APP_H 142 | -------------------------------------------------------------------------------- /src/powerkit_backlight.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include "powerkit_backlight.h" 10 | #include "powerkit_common.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define LOGIND_SESSION "org.freedesktop.login1.Session" 20 | #define LOGIND_PATH_SESSION "/org/freedesktop/login1/session/self" 21 | 22 | using namespace PowerKit; 23 | 24 | const QString Backlight::getDevice() 25 | { 26 | QString path = "/sys/class/backlight"; 27 | QDirIterator it(path, QDirIterator::Subdirectories); 28 | while (it.hasNext()) { 29 | QString foundDir = it.next(); 30 | if (foundDir.startsWith(QString("%1/radeon").arg(path))) { 31 | return foundDir; 32 | } else if (foundDir.startsWith(QString("%1/amdgpu").arg(path))) { 33 | return foundDir; 34 | } else if (foundDir.startsWith(QString("%1/intel").arg(path))) { 35 | return foundDir; 36 | } else if (foundDir.startsWith(QString("%1/acpi").arg(path))) { 37 | return foundDir; 38 | } 39 | } 40 | return QString(); 41 | } 42 | 43 | bool Backlight::canAdjustBrightness(const QString &device) 44 | { 45 | QFileInfo backlight(QString("%1/brightness").arg(device)); 46 | if (backlight.isWritable()) { return true; } 47 | return false; 48 | } 49 | 50 | bool Backlight::canAdjustBrightness() 51 | { 52 | return canAdjustBrightness(getDevice()); 53 | } 54 | 55 | int Backlight::getMaxBrightness(const QString &device) 56 | { 57 | int result = 0; 58 | QFile backlight(QString("%1/max_brightness").arg(device)); 59 | if (backlight.open(QIODevice::ReadOnly)) { 60 | result = backlight.readAll().trimmed().toInt(); 61 | backlight.close(); 62 | } 63 | return result; 64 | } 65 | 66 | int Backlight::getMaxBrightness() 67 | { 68 | return getMaxBrightness(getDevice()); 69 | } 70 | 71 | int Backlight::getCurrentBrightness(const QString &device) 72 | { 73 | int result = 0; 74 | QFile backlight(QString("%1/brightness").arg(device)); 75 | if (backlight.open(QIODevice::ReadOnly)) { 76 | result = backlight.readAll().trimmed().toInt(); 77 | backlight.close(); 78 | } 79 | return result; 80 | } 81 | 82 | int Backlight::getCurrentBrightness() 83 | { 84 | return getCurrentBrightness(getDevice()); 85 | } 86 | 87 | bool Backlight::setCurrentBrightness(const QString &device, int value) 88 | { 89 | if (!canAdjustBrightness(device)) { return false; } 90 | QFile backlight(QString("%1/brightness").arg(device)); 91 | if (backlight.open(QIODevice::WriteOnly|QIODevice::Truncate)) { 92 | QTextStream out(&backlight); 93 | if (value<1) { value = 1; } 94 | out << QString::number(value); 95 | backlight.close(); 96 | if (value == getCurrentBrightness(device)) { return true;} 97 | } 98 | return false; 99 | } 100 | 101 | bool Backlight::setCurrentBrightness(int value) 102 | { 103 | return setCurrentBrightness(getDevice(), value); 104 | } 105 | 106 | bool Backlight::setBrightness(const QString &device, 107 | int value) 108 | { 109 | QDBusInterface iface(POWERKIT_LOGIND_SERVICE, 110 | LOGIND_PATH_SESSION, 111 | LOGIND_SESSION, 112 | QDBusConnection::systemBus()); 113 | if (!iface.isValid()) { return false; } 114 | QDBusMessage reply = iface.call("SetBrightness", 115 | "backlight", 116 | device.split("/").takeLast(), 117 | (quint32)value); 118 | return reply.errorMessage().isEmpty(); 119 | } 120 | 121 | bool Backlight::setBrightness(int value) 122 | { 123 | return setBrightness(getDevice(), value); 124 | } 125 | -------------------------------------------------------------------------------- /src/powerkit_backlight.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_BACKLIGHT_H 10 | #define POWERKIT_BACKLIGHT_H 11 | 12 | #include 13 | 14 | namespace PowerKit 15 | { 16 | class Backlight 17 | { 18 | public: 19 | static const QString getDevice(); 20 | static bool canAdjustBrightness(const QString &device); 21 | static bool canAdjustBrightness(); 22 | static int getMaxBrightness(const QString &device); 23 | static int getMaxBrightness(); 24 | static int getCurrentBrightness(const QString &device); 25 | static int getCurrentBrightness(); 26 | static bool setCurrentBrightness(const QString &device, int value); // deprecated 27 | static bool setCurrentBrightness(int value); // deprecated 28 | static bool setBrightness(const QString &device, int value); 29 | static bool setBrightness(int value); 30 | }; 31 | } 32 | 33 | #endif // POWERKIT_BACKLIGHT_H 34 | -------------------------------------------------------------------------------- /src/powerkit_client.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include "powerkit_client.h" 10 | #include 11 | 12 | using namespace PowerKit; 13 | 14 | double Client::getBatteryLeft(QDBusInterface *iface) 15 | { 16 | if (!iface) { return -1; } 17 | qDebug() << "check for battery left"; 18 | if (!iface->isValid()) { return false; } 19 | QDBusMessage reply = iface->call("BatteryLeft"); 20 | const auto args = reply.arguments(); 21 | double ok = args.last().toDouble(); 22 | qDebug() << "we have battery left" << ok; 23 | return ok; 24 | } 25 | 26 | bool Client::hasBattery(QDBusInterface *iface) 27 | { 28 | if (!iface) { return false; } 29 | qDebug() << "check if we have any battery"; 30 | if (!iface->isValid()) { return false; } 31 | QDBusMessage reply = iface->call("HasBattery"); 32 | const auto args = reply.arguments(); 33 | bool ok = args.last().toBool(); 34 | qDebug() << "we have any battery?" << ok; 35 | return ok; 36 | } 37 | 38 | bool Client::onBattery(QDBusInterface *iface) 39 | { 40 | if (!iface) { return false; } 41 | qDebug() << "check if we are on battery"; 42 | if (!iface->isValid()) { return false; } 43 | QDBusMessage reply = iface->call("OnBattery"); 44 | const auto args = reply.arguments(); 45 | bool ok = args.last().toBool(); 46 | qDebug() << "we are on battery?" << ok; 47 | return ok; 48 | } 49 | 50 | qlonglong Client::timeToEmpty(QDBusInterface *iface) 51 | { 52 | if (!iface) { return -1; } 53 | qDebug() << "check for time to empty"; 54 | if (!iface->isValid()) { return false; } 55 | QDBusMessage reply = iface->call("TimeToEmpty"); 56 | const auto args = reply.arguments(); 57 | qlonglong ok = args.last().toLongLong(); 58 | qDebug() << "we have time to empty?" << ok; 59 | return ok; 60 | } 61 | 62 | qlonglong Client::timeToFull(QDBusInterface *iface) 63 | { 64 | if (!iface) { return -1; } 65 | qDebug() << "check for time to full"; 66 | if (!iface->isValid()) { return false; } 67 | QDBusMessage reply = iface->call("TimeToFull"); 68 | const auto args = reply.arguments(); 69 | qlonglong ok = args.last().toLongLong(); 70 | qDebug() << "we have time to full?" << ok; 71 | return ok; 72 | } 73 | 74 | bool Client::canHibernate(QDBusInterface *iface) 75 | { 76 | if (!iface) { return false; } 77 | qDebug() << "check if we can hibernate"; 78 | if (!iface->isValid()) { return false; } 79 | QDBusMessage reply = iface->call("CanHibernate"); 80 | const auto args = reply.arguments(); 81 | bool ok = args.last().toBool(); 82 | qDebug() << "we can hibernate?" << ok; 83 | return ok; 84 | } 85 | 86 | bool Client::canSuspend(QDBusInterface *iface) 87 | { 88 | if (!iface) { return false; } 89 | qDebug() << "check if we can suspend"; 90 | if (!iface->isValid()) { return false; } 91 | QDBusMessage reply = iface->call("CanSuspend"); 92 | const auto args = reply.arguments(); 93 | bool ok = args.last().toBool(); 94 | qDebug() << "we can suspend?" << ok; 95 | return ok; 96 | } 97 | 98 | bool Client::canRestart(QDBusInterface *iface) 99 | { 100 | if (!iface) { return false; } 101 | qDebug() << "check if we can restart"; 102 | if (!iface->isValid()) { return false; } 103 | QDBusMessage reply = iface->call("CanRestart"); 104 | const auto args = reply.arguments(); 105 | bool ok = args.last().toBool(); 106 | qDebug() << "we can restart?" << ok; 107 | return ok; 108 | } 109 | 110 | bool Client::canPowerOff(QDBusInterface *iface) 111 | { 112 | if (!iface) { return false; } 113 | qDebug() << "check if we can poweroff"; 114 | if (!iface->isValid()) { return false; } 115 | QDBusMessage reply = iface->call("CanPowerOff"); 116 | const auto args = reply.arguments(); 117 | bool ok = args.last().toBool(); 118 | qDebug() << "we can poweroff?" << ok; 119 | return ok; 120 | } 121 | 122 | bool Client::lidIsPresent(QDBusInterface *iface) 123 | { 124 | if (!iface) { return false; } 125 | qDebug() << "check if we have a lid"; 126 | if (!iface->isValid()) { return false; } 127 | QDBusMessage reply = iface->call("LidIsPresent"); 128 | const auto args = reply.arguments(); 129 | bool ok = args.last().toBool(); 130 | qDebug() << "we have a lid?" << ok; 131 | return ok; 132 | } 133 | 134 | bool Client::lockScreen(QDBusInterface *iface) 135 | { 136 | if (!iface) { return false; } 137 | if (!iface->isValid()) { return false; } 138 | const auto reply = iface->call("LockScreen"); 139 | return reply.errorMessage().isEmpty(); 140 | } 141 | 142 | bool Client::hibernate(QDBusInterface *iface) 143 | { 144 | if (!iface) { return false; } 145 | if (!iface->isValid()) { return false; } 146 | const auto reply = iface->call("Hibernate"); 147 | return reply.errorMessage().isEmpty(); 148 | } 149 | 150 | bool Client::suspend(QDBusInterface *iface) 151 | { 152 | if (!iface) { return false; } 153 | if (!iface->isValid()) { return false; } 154 | const auto reply = iface->call("Suspend"); 155 | return reply.errorMessage().isEmpty(); 156 | } 157 | 158 | bool Client::suspendThenHibernate(QDBusInterface *iface) 159 | { 160 | if (!iface) { return false; } 161 | if (!iface->isValid()) { return false; } 162 | const auto reply = iface->call("SuspendThenHibernate"); 163 | return reply.errorMessage().isEmpty(); 164 | } 165 | 166 | bool Client::restart(QDBusInterface *iface) 167 | { 168 | if (!iface) { return false; } 169 | qDebug() << "restart"; 170 | if (!iface->isValid()) { return false; } 171 | QDBusMessage reply = iface->call("Restart"); 172 | bool ok = reply.errorMessage().isEmpty(); 173 | qDebug() << "reply" << ok; 174 | return ok; 175 | } 176 | 177 | bool Client::poweroff(QDBusInterface *iface) 178 | { 179 | if (!iface) { return false; } 180 | qDebug() << "poweroff"; 181 | if (!iface->isValid()) { return false; } 182 | QDBusMessage reply = iface->call("PowerOff"); 183 | bool ok = reply.errorMessage().isEmpty(); 184 | qDebug() << "reply" << ok; 185 | return ok; 186 | } 187 | -------------------------------------------------------------------------------- /src/powerkit_client.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_CLIENT_H 10 | #define POWERKIT_CLIENT_H 11 | 12 | #include 13 | 14 | namespace PowerKit 15 | { 16 | class Client 17 | { 18 | public: 19 | static double getBatteryLeft(QDBusInterface *iface); 20 | static bool hasBattery(QDBusInterface *iface); 21 | static bool onBattery(QDBusInterface *iface); 22 | static qlonglong timeToEmpty(QDBusInterface *iface); 23 | static qlonglong timeToFull(QDBusInterface *iface); 24 | static bool canHibernate(QDBusInterface *iface); 25 | static bool canSuspend(QDBusInterface *iface); 26 | static bool canRestart(QDBusInterface *iface); 27 | static bool canPowerOff(QDBusInterface *iface); 28 | static bool lidIsPresent(QDBusInterface *iface); 29 | static bool lockScreen(QDBusInterface *iface); 30 | static bool hibernate(QDBusInterface *iface); 31 | static bool suspend(QDBusInterface *iface); 32 | static bool suspendThenHibernate(QDBusInterface *iface); 33 | static bool restart(QDBusInterface *iface); 34 | static bool poweroff(QDBusInterface *iface); 35 | }; 36 | } 37 | 38 | #endif // POWERKIT_CLIENT_H 39 | -------------------------------------------------------------------------------- /src/powerkit_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_COMMON_H 10 | #define POWERKIT_COMMON_H 11 | 12 | namespace PowerKit 13 | { 14 | enum randrAction 15 | { 16 | randrAuto, 17 | randrLeftOf, 18 | randrRightOf, 19 | randrAbove, 20 | randrBelow, 21 | randrSameAs 22 | }; 23 | 24 | enum suspendAction 25 | { 26 | suspendNone, 27 | suspendSleep, 28 | suspendHibernate, 29 | suspendShutdown, 30 | suspendHybrid, 31 | suspendSleepHibernate 32 | }; 33 | 34 | enum lidAction 35 | { 36 | lidNone, 37 | lidLock, 38 | lidSleep, 39 | lidHibernate, 40 | lidShutdown, 41 | lidHybridSleep, 42 | lidSleepHibernate 43 | }; 44 | 45 | enum criticalAction 46 | { 47 | criticalNone, 48 | criticalHibernate, 49 | criticalShutdown, 50 | criticalSuspend 51 | }; 52 | } 53 | 54 | #define POWERKIT_LID_BATTERY_ACTION PowerKit::lidSleep 55 | #define POWERKIT_LID_AC_ACTION PowerKit::lidLock 56 | #define POWERKIT_CRITICAL_ACTION PowerKit::criticalNone 57 | #define POWERKIT_SUSPEND_BATTERY_ACTION PowerKit::suspendSleep 58 | #define POWERKIT_SUSPEND_AC_ACTION PowerKit::suspendNone 59 | #define POWERKIT_BACKLIGHT_STEP 10 // +/- 60 | #define POWERKIT_LOW_BATTERY 5 // % over critical 61 | #define POWERKIT_CRITICAL_BATTERY 10 // % 62 | #define POWERKIT_AUTO_SLEEP_BATTERY 15 // min 63 | #define POWERKIT_ICON "ac-adapter" 64 | #define POWERKIT_SERVICE "org.freedesktop.PowerKit" 65 | #define POWERKIT_PATH "/PowerKit" 66 | #define POWERKIT_MANAGER "org.freedesktop.PowerKit.Manager" 67 | #define POWERKIT_CONFIG "org.freedesktop.PowerKit.Configuration" 68 | #define POWERKIT_LOGIND_SERVICE "org.freedesktop.login1" 69 | #define POWERKIT_UPOWER_SERVICE "org.freedesktop.UPower" 70 | #define POWERKIT_DBUS_PROPERTIES "org.freedesktop.DBus.Properties" 71 | #define POWERKIT_SCREENSAVER_LOCK_CMD "xsecurelock" 72 | #define POWERKIT_SCREENSAVER_TIMEOUT_BLANK 300 73 | 74 | #endif // POWERKIT_COMMON_H 75 | -------------------------------------------------------------------------------- /src/powerkit_cpu.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include "powerkit_cpu.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #define LINUX_CPU_SYS "/sys/devices/system/cpu" 16 | #define LINUX_CPU_DIR "cpufreq" 17 | #define LINUX_CPU_FREQUENCIES "scaling_available_frequencies" 18 | #define LINUX_CPU_FREQUENCY "scaling_cur_freq" 19 | #define LINUX_CPU_FREQUENCY_MAX "scaling_max_freq" 20 | #define LINUX_CPU_FREQUENCY_MIN "scaling_min_freq" 21 | #define LINUX_CPU_GOVERNORS "scaling_available_governors" 22 | #define LINUX_CPU_GOVERNOR "scaling_governor" 23 | #define LINUX_CPU_SET_SPEED "scaling_setspeed" 24 | #define LINUX_CPU_PSTATE "intel_pstate" 25 | #define LINUX_CPU_PSTATE_STATUS "status" 26 | #define LINUX_CPU_PSTATE_NOTURBO "no_turbo" 27 | #define LINUX_CPU_PSTATE_MAX_PERF "max_perf_pct" 28 | #define LINUX_CPU_PSTATE_MIN_PERF "min_perf_pct" 29 | 30 | #define LINUX_CORETEMP "/sys/class/hwmon/hwmon%1" 31 | #define LINUX_CORETEMP_CRIT "temp%1_crit" 32 | #define LINUX_CORETEMP_INPUT "temp%1_input" 33 | #define LINUX_CORETEMP_LABEL "temp%1_label" 34 | #define LINUX_CORETEMP_MAX "temp%1_max" 35 | 36 | #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) 37 | #define QT_SKIP_EMPTY Qt::SkipEmptyParts 38 | #else 39 | #define QT_SKIP_EMPTY QString::SkipEmptyParts 40 | #endif 41 | 42 | using namespace PowerKit; 43 | 44 | int Cpu::getTotal() 45 | { 46 | int counter = 0; 47 | while(1) { 48 | if (QFile::exists(QString("%1/cpu%2") 49 | .arg(LINUX_CPU_SYS) 50 | .arg(counter))) { counter++; } 51 | else { break; } 52 | } 53 | if (counter>0) { return counter; } 54 | return -1; 55 | } 56 | 57 | const QString Cpu::getGovernor(int cpu) 58 | { 59 | QString result; 60 | QFile gov(QString("%1/cpu%2/%3/%4") 61 | .arg(LINUX_CPU_SYS) 62 | .arg(cpu) 63 | .arg(LINUX_CPU_DIR) 64 | .arg(LINUX_CPU_GOVERNOR)); 65 | if (!gov.exists()) { return result; } 66 | if (gov.open(QIODevice::ReadOnly|QIODevice::Text)) { 67 | result = gov.readAll().trimmed(); 68 | gov.close(); 69 | } 70 | return result; 71 | } 72 | 73 | const QStringList Cpu::getGovernors() 74 | { 75 | QStringList result; 76 | for (int i=0;i freqMax) { val = QString::number(freqMax); } 229 | else if (freq.toInt() < freqMin) { val = QString::number(freqMin); } 230 | QFile file(QString("%1/cpu%2/%3/%4").arg(LINUX_CPU_SYS, 231 | QString::number(cpu), 232 | LINUX_CPU_DIR, 233 | LINUX_CPU_SET_SPEED)); 234 | if (file.open(QIODevice::WriteOnly|QIODevice::Truncate)) { 235 | QTextStream out(&file); 236 | out << val; 237 | file.close(); 238 | if (val == getFrequency(cpu)) { return true; } 239 | } 240 | return false; 241 | } 242 | 243 | bool Cpu::setFrequency(const QString &freq) 244 | { 245 | if (hasPState()) { return false; } 246 | if (!frequencyExists(freq)) { return false; } 247 | bool failed = false; 248 | for (int i=0;i Cpu::getCoreTemp() 373 | { 374 | QPair temp = {0.0, 0.0}; 375 | if (!hasCoreTemp()) { return temp; } 376 | 377 | int temps = 1; 378 | int hwmons = 10; 379 | for (int hwmon = 0; hwmon < hwmons; ++hwmon) { 380 | bool foundPackage = false; 381 | QFile file(QString("%1/%2").arg(QString(LINUX_CORETEMP).arg(hwmon), 382 | QString(LINUX_CORETEMP_LABEL).arg(temps))); 383 | if (file.open(QIODevice::ReadOnly|QIODevice::Text)) { 384 | QString label = file.readAll().trimmed(); 385 | if (label.startsWith("Package")) { foundPackage = true; } 386 | file.close(); 387 | } 388 | if (foundPackage) { 389 | QFile fileInput(QString("%1/%2").arg(QString(LINUX_CORETEMP).arg(hwmon), 390 | QString(LINUX_CORETEMP_INPUT).arg(temps))); 391 | if (fileInput.open(QIODevice::ReadOnly|QIODevice::Text)) { 392 | double ctemp = fileInput.readAll().trimmed().toDouble(); 393 | file.close(); 394 | if (ctemp > temp.first) { 395 | temp.first = ctemp; 396 | } 397 | } 398 | QFile fileMax(QString("%1/%2").arg(QString(LINUX_CORETEMP).arg(hwmon), 399 | QString(LINUX_CORETEMP_MAX).arg(temps))); 400 | if (fileMax.open(QIODevice::ReadOnly|QIODevice::Text)) { 401 | double mtemp = fileMax.readAll().trimmed().toDouble(); 402 | file.close(); 403 | if (mtemp > temp.second) { 404 | temp.second = mtemp; 405 | } 406 | } 407 | if (temp.first > 0.0 && temp.second > 0.0) { break; } 408 | } 409 | } 410 | return temp; 411 | } 412 | 413 | const QPair Cpu::getCpuFreqLabel() 414 | { 415 | QStringList freqs = getFrequencies(); 416 | int currentCpuFreq = 0; 417 | double currentFancyFreq = 0.; 418 | for (int i=0; i < freqs.size(); ++i) { 419 | auto freq = freqs.at(i).toLong(); 420 | if (freq > currentCpuFreq) { 421 | currentCpuFreq = freq; 422 | currentFancyFreq = freqs.at(i).toDouble(); 423 | } 424 | } 425 | 426 | QPair result; 427 | 428 | int freqMin = Cpu::getMinFrequency(); 429 | int freqMax = Cpu::getMaxFrequency(); 430 | int progress; 431 | if (freqMax == freqMin) { 432 | progress = 100; 433 | } else { 434 | progress = ((currentCpuFreq - freqMin) * 100) / (freqMax - freqMin); 435 | } 436 | 437 | result.first = progress; 438 | result.second = QString("%1\nGhz").arg(QString::number(currentFancyFreq / 1000000, 'f', 2)); 439 | return result; 440 | } 441 | 442 | const QPair Cpu::getCpuTempLabel() 443 | { 444 | QPair result; 445 | const auto temps = getCoreTemp(); 446 | int progress = (temps.first * 100) / temps.second; 447 | 448 | result.first = progress; 449 | result.second = QString("%1°C").arg(QString::number(temps.first / 1000, 'f', 0)); 450 | return result; 451 | } 452 | -------------------------------------------------------------------------------- /src/powerkit_cpu.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_CPU_H 10 | #define POWERKIT_CPU_H 11 | 12 | #include 13 | #include 14 | 15 | namespace PowerKit 16 | { 17 | class Cpu 18 | { 19 | public: 20 | static int getTotal(); 21 | 22 | static const QString getGovernor(int cpu); 23 | static const QStringList getGovernors(); 24 | static const QStringList getAvailableGovernors(); 25 | static bool governorExists(const QString &gov); 26 | static bool setGovernor(const QString &gov, int cpu); 27 | static bool setGovernor(const QString &gov); 28 | 29 | static const QString getFrequency(int cpu); 30 | static const QStringList getFrequencies(); 31 | static const QStringList getAvailableFrequency(); 32 | static int getMinFrequency(); 33 | static int getMaxFrequency(); 34 | static int getScalingFrequency(int cpu, int scale); 35 | static bool frequencyExists(const QString &freq); 36 | static bool setFrequency(const QString &freq, int cpu); 37 | static bool setFrequency(const QString &freq); 38 | 39 | static bool hasPState(); 40 | static bool hasPStateTurbo(); 41 | static bool setPStateTurbo(bool turbo); 42 | static int getPStateMax(); 43 | static int getPStateMin(); 44 | static bool setPStateMax(int maxState); 45 | static bool setPStateMin(int minState); 46 | static bool setPState(int min, int max); 47 | 48 | static bool hasCoreTemp(); 49 | static QPair getCoreTemp(); 50 | 51 | static const QPair getCpuFreqLabel(); 52 | static const QPair getCpuTempLabel(); 53 | }; 54 | } 55 | 56 | #endif // POWERKIT_CPU_H 57 | -------------------------------------------------------------------------------- /src/powerkit_device.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include "powerkit_device.h" 10 | #include "powerkit_common.h" 11 | 12 | #include 13 | #include 14 | 15 | #define PROP_CHANGED "PropertiesChanged" 16 | #define PROP_DEV_MODEL "Model" 17 | #define PROP_DEV_CAPACITY "Capacity" 18 | #define PROP_DEV_IS_RECHARGE "IsRechargeable" 19 | #define PROP_DEV_PRESENT "IsPresent" 20 | #define PROP_DEV_PERCENT "Percentage" 21 | #define PROP_DEV_ENERGY_FULL_DESIGN "EnergyFullDesign" 22 | #define PROP_DEV_ENERGY_FULL "EnergyFull" 23 | #define PROP_DEV_ENERGY_EMPTY "EnergyEmpty" 24 | #define PROP_DEV_ENERGY "Energy" 25 | #define PROP_DEV_ONLINE "Online" 26 | #define PROP_DEV_POWER_SUPPLY "PowerSupply" 27 | #define PROP_DEV_TIME_TO_EMPTY "TimeToEmpty" 28 | #define PROP_DEV_TIME_TO_FULL "TimeToFull" 29 | #define PROP_DEV_TYPE "Type" 30 | #define PROP_DEV_VENDOR "Vendor" 31 | #define PROP_DEV_NATIVEPATH "NativePath" 32 | 33 | #define DBUS_CHANGED "Changed" 34 | #define DBUS_DEVICE "Device" 35 | 36 | using namespace PowerKit; 37 | 38 | Device::Device(const QString block, QObject *parent) 39 | : QObject(parent) 40 | , path(block) 41 | , isRechargable(false) 42 | , isPresent(false) 43 | , percentage(0) 44 | , online(false) 45 | , hasPowerSupply(false) 46 | , isBattery(false) 47 | , isAC(false) 48 | , capacity(0) 49 | , energy(0) 50 | , energyFullDesign(0) 51 | , energyFull(0) 52 | , energyEmpty(0) 53 | , dbus(nullptr) 54 | , dbusp(nullptr) 55 | { 56 | QDBusConnection system = QDBusConnection::systemBus(); 57 | dbus = new QDBusInterface(POWERKIT_UPOWER_SERVICE, 58 | path, 59 | QString("%1.%2").arg(POWERKIT_UPOWER_SERVICE, DBUS_DEVICE), 60 | system, 61 | parent); 62 | system.connect(dbus->service(), 63 | dbus->path(), 64 | QString("%1.%2").arg(POWERKIT_UPOWER_SERVICE, DBUS_DEVICE), 65 | DBUS_CHANGED, 66 | this, 67 | SLOT(updateDeviceProperties())); 68 | dbusp = new QDBusInterface(POWERKIT_UPOWER_SERVICE, 69 | path, 70 | POWERKIT_DBUS_PROPERTIES, 71 | system, 72 | parent); 73 | system.connect(dbusp->service(), 74 | dbusp->path(), 75 | POWERKIT_DBUS_PROPERTIES, 76 | PROP_CHANGED, 77 | this, 78 | SLOT(updateDeviceProperties())); 79 | if (name.isEmpty()) { name = path.split("/").takeLast(); } 80 | updateDeviceProperties(); 81 | } 82 | 83 | // get device properties 84 | void Device::updateDeviceProperties() 85 | { 86 | if (!dbus->isValid()) { return; } 87 | 88 | model = dbus->property(PROP_DEV_MODEL).toString(); 89 | capacity = dbus->property(PROP_DEV_CAPACITY).toDouble(); 90 | isRechargable = dbus->property(PROP_DEV_IS_RECHARGE).toBool(); 91 | isPresent = dbus->property(PROP_DEV_PRESENT).toBool(); 92 | percentage = dbus->property(PROP_DEV_PERCENT).toDouble(); 93 | energyFullDesign = dbus->property(PROP_DEV_ENERGY_FULL_DESIGN).toDouble(); 94 | energyFull = dbus->property(PROP_DEV_ENERGY_FULL).toDouble(); 95 | energyEmpty = dbus->property(PROP_DEV_ENERGY_EMPTY).toDouble(); 96 | energy = dbus->property(PROP_DEV_ENERGY).toDouble(); 97 | online = dbus->property(PROP_DEV_ONLINE).toBool(); 98 | hasPowerSupply = dbus->property(PROP_DEV_POWER_SUPPLY).toBool(); 99 | timeToEmpty = dbus->property(PROP_DEV_TIME_TO_EMPTY).toLongLong(); 100 | timeToFull = dbus->property(PROP_DEV_TIME_TO_FULL).toLongLong(); 101 | type = (DeviceType)dbus->property(PROP_DEV_TYPE).toUInt(); 102 | 103 | if (type == DeviceBattery) { isBattery = true; } 104 | else { 105 | isBattery = false; 106 | if (type == DeviceLinePower) { isAC = true; } 107 | else { isAC = false; } 108 | } 109 | 110 | vendor = dbus->property(PROP_DEV_VENDOR).toString(); 111 | nativePath = dbus->property(PROP_DEV_NATIVEPATH).toString(); 112 | 113 | emit deviceChanged(path); 114 | } 115 | 116 | void Device::update() 117 | { 118 | updateDeviceProperties(); 119 | } 120 | 121 | void Device::updateBattery() 122 | { 123 | percentage = dbus->property(PROP_DEV_PERCENT).toDouble(); 124 | timeToEmpty = dbus->property(PROP_DEV_TIME_TO_EMPTY).toLongLong(); 125 | timeToFull = dbus->property(PROP_DEV_TIME_TO_FULL).toLongLong(); 126 | } 127 | -------------------------------------------------------------------------------- /src/powerkit_device.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_DEVICE_H 10 | #define POWERKIT_DEVICE_H 11 | 12 | #include 13 | #include 14 | 15 | namespace PowerKit 16 | { 17 | class Device : public QObject 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | enum DeviceType { 23 | DeviceUnknown, 24 | DeviceLinePower, 25 | DeviceBattery, 26 | DeviceUps, 27 | DeviceMonitor, 28 | DeviceMouse, 29 | DeviceKeyboard, 30 | DevicePda, 31 | DevicePhone 32 | }; 33 | explicit Device(const QString block, 34 | QObject *parent = nullptr); 35 | QString name; 36 | QString path; 37 | QString model; 38 | DeviceType type; 39 | bool isRechargable; 40 | bool isPresent; 41 | double percentage; 42 | bool online; 43 | bool hasPowerSupply; 44 | bool isBattery; 45 | bool isAC; 46 | QString vendor; 47 | QString nativePath; 48 | double capacity; 49 | double energy; 50 | double energyFullDesign; 51 | double energyFull; 52 | double energyEmpty; 53 | qlonglong timeToEmpty; 54 | qlonglong timeToFull; 55 | 56 | private: 57 | QDBusInterface *dbus; 58 | QDBusInterface *dbusp; 59 | 60 | signals: 61 | void deviceChanged(const QString &devicePath); 62 | 63 | private slots: 64 | void updateDeviceProperties(); 65 | 66 | public slots: 67 | void update(); 68 | void updateBattery(); 69 | }; 70 | } 71 | 72 | #endif // POWERKIT_DEVICE_H 73 | -------------------------------------------------------------------------------- /src/powerkit_dialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include "powerkit_dialog.h" 10 | #include "powerkit_common.h" 11 | #include "powerkit_theme.h" 12 | #include "powerkit_settings.h" 13 | #include "powerkit_backlight.h" 14 | #include "powerkit_client.h" 15 | #include "powerkit_cpu.h" 16 | 17 | #include 18 | 19 | #define MAX_WIDTH 175 20 | 21 | using namespace PowerKit; 22 | 23 | Dialog::Dialog(QWidget *parent, 24 | bool quitOnClose) 25 | : QDialog(parent) 26 | , cpuTimer(nullptr) 27 | , dbus(nullptr) 28 | , lidActionBattery(nullptr) 29 | , lidActionAC(nullptr) 30 | , criticalActionBattery(nullptr) 31 | , criticalBattery(nullptr) 32 | , autoSleepBattery(nullptr) 33 | , autoSleepAC(nullptr) 34 | , showNotifications(nullptr) 35 | , showSystemTray(nullptr) 36 | , disableLidAction(nullptr) 37 | , autoSleepBatteryAction(nullptr) 38 | , autoSleepACAction(nullptr) 39 | , backlightSliderBattery(nullptr) 40 | , backlightSliderAC(nullptr) 41 | , backlightBatteryCheck(nullptr) 42 | , backlightACCheck(nullptr) 43 | , backlightBatteryLowerCheck(nullptr) 44 | , backlightACHigherCheck(nullptr) 45 | , warnOnLowBattery(nullptr) 46 | , warnOnVeryLowBattery(nullptr) 47 | , lidActionACLabel(nullptr) 48 | , lidActionBatteryLabel(nullptr) 49 | , batteryBacklightLabel(nullptr) 50 | , acBacklightLabel(nullptr) 51 | , backlightMouseWheel(nullptr) 52 | , batteryStatusLabel(nullptr) 53 | , cpuFreqLabel(nullptr) 54 | , cpuTempLabel(nullptr) 55 | , screensaverBlank(nullptr) 56 | , hasCpuCoreTemp(false) 57 | , hasBattery(false) 58 | { 59 | // setup dialog 60 | if (quitOnClose) { setAttribute(Qt::WA_QuitOnClose, true); } 61 | setWindowTitle(tr("Power Manager")); 62 | setMinimumSize(QSize(680, 360)); 63 | 64 | // setup cpu timer 65 | cpuTimer = new QTimer(this); 66 | cpuTimer->setInterval(1000); 67 | connect(cpuTimer, 68 | SIGNAL(timeout()), 69 | this, 70 | SLOT(drawCpu())); 71 | cpuTimer->start(); 72 | 73 | // setup dbus 74 | QDBusConnection session = QDBusConnection::sessionBus(); 75 | dbus = new QDBusInterface(POWERKIT_SERVICE, 76 | POWERKIT_PATH, 77 | POWERKIT_MANAGER, 78 | session, this); 79 | if (!dbus->isValid()) { 80 | QMessageBox::warning(this, 81 | tr("powerkit not running"), 82 | tr("powerkit is not running, please start powerkit before running this application.")); 83 | QTimer::singleShot(100, qApp, SLOT(quit())); 84 | return; 85 | } 86 | 87 | // detect device changes 88 | connect(dbus, SIGNAL(UpdatedDevices()), 89 | this, SLOT(handleUpdatedDevices())); 90 | 91 | // trigger generation of powerkit.conf if not exists 92 | Settings::getConf(); 93 | 94 | setupWidgets(); 95 | populateWidgets(); 96 | loadSettings(); 97 | connectWidgets(); 98 | handleUpdatedDevices(); 99 | } 100 | 101 | Dialog::~Dialog() 102 | { 103 | const auto lastGeo = Settings::getValue(CONF_DIALOG).toByteArray(); 104 | const auto newGeo = saveGeometry(); 105 | if (lastGeo != newGeo) { 106 | Settings::setValue(CONF_DIALOG, newGeo); 107 | } 108 | } 109 | 110 | void Dialog::setupWidgets() 111 | { 112 | // setup theme 113 | Theme::setAppTheme(); 114 | Theme::setIconTheme(); 115 | setStyleSheet("QLabel { font-weight: bold; }"); 116 | setWindowIcon(QIcon::fromTheme(POWERKIT_ICON)); 117 | 118 | // setup widgets 119 | const auto layout = new QVBoxLayout(this); 120 | layout->setMargin(5); 121 | layout->setSpacing(0); 122 | 123 | // status widgets 124 | const auto statusWidget = new QWidget(this); 125 | statusWidget->setSizePolicy(QSizePolicy::Expanding, 126 | QSizePolicy::Fixed); 127 | const auto statusLayout = new QHBoxLayout(statusWidget); 128 | 129 | batteryStatusLabel = new QLabel(this); 130 | 131 | int iconLabelSize = 64; 132 | batteryStatusLabel->setMaximumSize(iconLabelSize, iconLabelSize); 133 | batteryStatusLabel->setMinimumSize(iconLabelSize, iconLabelSize); 134 | 135 | cpuFreqLabel = new QLabel(this); 136 | cpuFreqLabel->setMaximumSize(iconLabelSize, iconLabelSize); 137 | cpuFreqLabel->setMinimumSize(iconLabelSize, iconLabelSize); 138 | 139 | cpuTempLabel = new QLabel(this); 140 | cpuTempLabel->setMaximumSize(iconLabelSize, iconLabelSize); 141 | cpuTempLabel->setMinimumSize(iconLabelSize, iconLabelSize); 142 | 143 | statusLayout->addWidget(batteryStatusLabel); 144 | statusLayout->addWidget(cpuFreqLabel); 145 | statusLayout->addWidget(cpuTempLabel); 146 | 147 | // battery 148 | const auto batteryContainer = new QGroupBox(this); 149 | batteryContainer->setTitle(tr("On Battery")); 150 | batteryContainer->setSizePolicy(QSizePolicy::Expanding, 151 | QSizePolicy::Expanding); 152 | const auto batteryContainerLayout = new QVBoxLayout(batteryContainer); 153 | batteryContainerLayout->setSpacing(0); 154 | 155 | const auto lidActionBatteryContainer = new QWidget(this); 156 | const auto lidActionBatteryContainerLayout = new QHBoxLayout(lidActionBatteryContainer); 157 | lidActionBatteryContainerLayout->setMargin(0); 158 | 159 | lidActionBattery = new QComboBox(this); 160 | lidActionBattery->setMaximumWidth(MAX_WIDTH); 161 | lidActionBattery->setMinimumWidth(MAX_WIDTH); 162 | 163 | lidActionBatteryLabel = new QLabel(this); 164 | lidActionBatteryLabel->setText(tr("Lid action")); 165 | lidActionBatteryLabel->setToolTip(tr("What to do when the lid is closed and running on battery.")); 166 | 167 | lidActionBatteryContainerLayout->addWidget(lidActionBatteryLabel); 168 | lidActionBatteryContainerLayout->addStretch(); 169 | lidActionBatteryContainerLayout->addWidget(lidActionBattery); 170 | 171 | const auto criticalBatteryContainer = new QWidget(this); 172 | const auto criticalBatteryContainerLayout = new QHBoxLayout(criticalBatteryContainer); 173 | criticalBatteryContainerLayout->setMargin(0); 174 | 175 | criticalBattery = new QSpinBox(this); 176 | criticalBattery->setMaximumWidth(MAX_WIDTH); 177 | criticalBattery->setMinimumWidth(MAX_WIDTH); 178 | criticalBattery->setMinimum(0); 179 | criticalBattery->setMaximum(99); 180 | criticalBattery->setSuffix(tr(" %")); 181 | criticalBattery->setPrefix(tr("At ")); 182 | 183 | const auto criticalBatteryLabel = new QLabel(this); 184 | const auto criticalActionBatteryContainer = new QWidget(this); 185 | criticalActionBatteryContainer->setContentsMargins(0, 0, 0, 0); 186 | 187 | const auto criticalActionBatteryContainerLayout = new QVBoxLayout(criticalActionBatteryContainer); 188 | criticalActionBatteryContainerLayout->setMargin(0); 189 | 190 | criticalActionBatteryContainerLayout->setMargin(0); 191 | criticalActionBatteryContainerLayout->setSpacing(0); 192 | criticalActionBattery = new QComboBox(this); 193 | criticalActionBattery->setMaximumWidth(MAX_WIDTH); 194 | criticalActionBattery->setMinimumWidth(MAX_WIDTH); 195 | criticalActionBatteryContainerLayout->addWidget(criticalBattery); 196 | criticalActionBatteryContainerLayout->addWidget(criticalActionBattery); 197 | 198 | criticalBatteryLabel->setText(tr("Critical Action")); 199 | criticalBatteryLabel->setToolTip(tr("What to do when your battery is critical.")); 200 | criticalBatteryContainerLayout->addWidget(criticalBatteryLabel); 201 | criticalBatteryContainerLayout->addStretch(); 202 | criticalBatteryContainerLayout->addWidget(criticalActionBatteryContainer); 203 | 204 | const auto sleepBatteryContainer = new QWidget(this); 205 | const auto sleepBatteryContainerLayout = new QHBoxLayout(sleepBatteryContainer); 206 | sleepBatteryContainerLayout->setMargin(0); 207 | 208 | autoSleepBattery = new QSpinBox(this); 209 | autoSleepBattery->setMaximumWidth(MAX_WIDTH); 210 | autoSleepBattery->setMinimumWidth(MAX_WIDTH); 211 | autoSleepBattery->setMinimum(0); 212 | autoSleepBattery->setMaximum(1000); 213 | autoSleepBattery->setSuffix(QString(" %1").arg(tr("min"))); 214 | autoSleepBattery->setPrefix(QString("%1 ").arg(tr("After"))); 215 | 216 | const auto sleepBatteryLabel = new QLabel(this); 217 | const auto sleepActionBatteryContainer = new QWidget(this); 218 | const auto sleepActionBatteryContainerLayout = new QVBoxLayout(sleepActionBatteryContainer); 219 | 220 | sleepActionBatteryContainer->setContentsMargins(0, 0, 0, 0); 221 | sleepActionBatteryContainerLayout->setMargin(0); 222 | sleepActionBatteryContainerLayout->setSpacing(0); 223 | autoSleepBatteryAction = new QComboBox(this); 224 | autoSleepBatteryAction->setMaximumWidth(MAX_WIDTH); 225 | autoSleepBatteryAction->setMinimumWidth(MAX_WIDTH); 226 | sleepActionBatteryContainerLayout->addWidget(autoSleepBattery); 227 | sleepActionBatteryContainerLayout->addWidget(autoSleepBatteryAction); 228 | 229 | sleepBatteryLabel->setText(tr("Suspend Action")); 230 | sleepBatteryLabel->setToolTip(tr("Enable automatically suspend when on battery.")); 231 | sleepBatteryContainerLayout->addWidget(sleepBatteryLabel); 232 | sleepBatteryContainerLayout->addStretch(); 233 | sleepBatteryContainerLayout->addWidget(sleepActionBatteryContainer); 234 | 235 | // backlight battery 236 | backlightSliderBattery = new QSlider(this); 237 | backlightSliderBattery->setOrientation(Qt::Horizontal); 238 | backlightSliderBattery->setMinimum(1); 239 | backlightSliderBattery->setMaximum(1); 240 | backlightSliderBattery->setValue(0); 241 | 242 | backlightBatteryCheck = new QCheckBox(this); 243 | backlightBatteryCheck->setCheckable(true); 244 | backlightBatteryCheck->setChecked(false); 245 | backlightBatteryCheck->setToolTip(tr("Enable/Disable brightness override on battery.")); 246 | backlightBatteryCheck->setText(QString(" ")); // qt ui bug workaround 247 | 248 | backlightBatteryLowerCheck = new QCheckBox(this); 249 | backlightBatteryLowerCheck->setCheckable(true); 250 | backlightBatteryLowerCheck->setChecked(false); 251 | backlightBatteryLowerCheck->setText(tr("Don't apply if lower")); 252 | backlightBatteryLowerCheck->setToolTip(tr("If your current brightness value is lower" 253 | " do not apply a brightness override (on battery).")); 254 | 255 | const auto backlightSliderBatteryContainer = new QWidget(this); 256 | const auto backlightSliderBatteryLayout = new QHBoxLayout(backlightSliderBatteryContainer); 257 | backlightSliderBatteryContainer->setContentsMargins(0, 0, 0, 0); 258 | backlightSliderBatteryLayout->setMargin(0); 259 | 260 | backlightSliderBatteryLayout->addWidget(backlightBatteryCheck); 261 | backlightSliderBatteryLayout->addWidget(backlightSliderBattery); 262 | 263 | const auto batteryBacklightOptContainer = new QWidget(this); 264 | const auto batteryBacklightOptContainerLayout = new QVBoxLayout(batteryBacklightOptContainer); 265 | 266 | batteryBacklightOptContainer->setContentsMargins(0, 0, 0, 0); 267 | batteryBacklightOptContainer->setMaximumWidth(MAX_WIDTH); 268 | batteryBacklightOptContainer->setMinimumWidth(MAX_WIDTH); 269 | batteryBacklightOptContainerLayout->setMargin(0); 270 | batteryBacklightOptContainerLayout->setContentsMargins(0, 0, 0, 0); 271 | batteryBacklightOptContainerLayout->addWidget(backlightSliderBatteryContainer); 272 | batteryBacklightOptContainerLayout->addWidget(backlightBatteryLowerCheck); 273 | 274 | const auto batteryBacklightContainer = new QWidget(this); 275 | const auto batteryBacklightContainerLayout = new QHBoxLayout(batteryBacklightContainer); 276 | batteryBacklightContainerLayout->setMargin(0); 277 | 278 | batteryBacklightLabel = new QLabel(this); 279 | batteryBacklightLabel->setText(tr("Brightness")); 280 | batteryBacklightLabel->setToolTip(tr("Override brightness when switched to battery power.")); 281 | 282 | batteryBacklightContainerLayout->addWidget(batteryBacklightLabel); 283 | batteryBacklightContainerLayout->addStretch(); 284 | batteryBacklightContainerLayout->addWidget(batteryBacklightOptContainer); 285 | 286 | // add battery widgets to container 287 | batteryContainerLayout->addWidget(lidActionBatteryContainer); 288 | batteryContainerLayout->addSpacing(10); 289 | batteryContainerLayout->addWidget(sleepBatteryContainer); 290 | batteryContainerLayout->addSpacing(10); 291 | batteryContainerLayout->addWidget(criticalBatteryContainer); 292 | batteryContainerLayout->addSpacing(10); 293 | batteryContainerLayout->addStretch(); 294 | batteryContainerLayout->addWidget(batteryBacklightContainer); 295 | 296 | // AC 297 | const auto acContainer = new QGroupBox(this); 298 | acContainer->setTitle(tr("On AC")); 299 | const auto acContainerLayout = new QVBoxLayout(acContainer); 300 | acContainerLayout->setSpacing(0); 301 | 302 | const auto lidActionACContainer = new QWidget(this); 303 | const auto lidActionACContainerLayout = new QHBoxLayout(lidActionACContainer); 304 | lidActionACContainerLayout->setMargin(0); 305 | 306 | lidActionAC = new QComboBox(this); 307 | lidActionAC->setMaximumWidth(MAX_WIDTH); 308 | lidActionAC->setMinimumWidth(MAX_WIDTH); 309 | lidActionACLabel = new QLabel(this); 310 | 311 | lidActionACLabel->setText(tr("Lid action")); 312 | lidActionACLabel->setToolTip(tr("What to do when the lid is closed and running on AC.")); 313 | lidActionACContainerLayout->addWidget(lidActionACLabel); 314 | lidActionACContainerLayout->addStretch(); 315 | lidActionACContainerLayout->addWidget(lidActionAC); 316 | acContainerLayout->addWidget(lidActionACContainer); 317 | 318 | const auto sleepACContainer = new QWidget(this); 319 | const auto sleepACContainerLayout = new QHBoxLayout(sleepACContainer); 320 | sleepACContainerLayout->setMargin(0); 321 | 322 | autoSleepAC = new QSpinBox(this); 323 | autoSleepAC->setMaximumWidth(MAX_WIDTH); 324 | autoSleepAC->setMinimumWidth(MAX_WIDTH); 325 | autoSleepAC->setMinimum(0); 326 | autoSleepAC->setMaximum(1000); 327 | autoSleepAC->setSuffix(QString(" %1").arg(tr("min"))); 328 | autoSleepAC->setPrefix(QString("%1 ").arg(tr("After"))); 329 | 330 | const auto sleepACLabel = new QLabel(this); 331 | 332 | sleepACContainerLayout->addWidget(sleepACLabel); 333 | acContainerLayout->addWidget(sleepACContainer); 334 | 335 | const auto sleepActionACContainer = new QWidget(this); 336 | const auto sleepActionACContainerLayout = new QVBoxLayout(sleepActionACContainer); 337 | 338 | sleepActionACContainer->setContentsMargins(0, 0, 0, 0); 339 | sleepActionACContainerLayout->setMargin(0); 340 | sleepActionACContainerLayout->setSpacing(0); 341 | autoSleepACAction = new QComboBox(this); 342 | autoSleepACAction->setMaximumWidth(MAX_WIDTH); 343 | autoSleepACAction->setMinimumWidth(MAX_WIDTH); 344 | sleepActionACContainerLayout->addWidget(autoSleepAC); 345 | sleepActionACContainerLayout->addWidget(autoSleepACAction); 346 | 347 | sleepACLabel->setText(tr("Suspend Action")); 348 | sleepACLabel->setToolTip(tr("Enable automatically suspend when on AC.")); 349 | sleepACContainerLayout->addWidget(sleepACLabel); 350 | sleepACContainerLayout->addStretch(); 351 | sleepACContainerLayout->addWidget(sleepActionACContainer); 352 | 353 | // backlight ac 354 | backlightSliderAC = new QSlider(this); 355 | backlightSliderAC->setOrientation(Qt::Horizontal); 356 | backlightSliderAC->setMinimum(1); 357 | backlightSliderAC->setMaximum(1); 358 | backlightSliderAC->setValue(0); 359 | 360 | backlightACCheck = new QCheckBox(this); 361 | backlightACCheck->setCheckable(true); 362 | backlightACCheck->setChecked(false); 363 | backlightACCheck->setToolTip(tr("Enable/Disable brightness override on AC.")); 364 | backlightACCheck->setText(QString(" ")); // qt ui bug workaround 365 | 366 | backlightACHigherCheck = new QCheckBox(this); 367 | backlightACHigherCheck->setCheckable(true); 368 | backlightACHigherCheck->setChecked(false); 369 | backlightACHigherCheck->setText(tr("Don't apply if higher")); 370 | backlightACHigherCheck->setToolTip(tr("If your current brightness value is higher" 371 | " do not apply a brightness override (on AC).")); 372 | 373 | const auto backlightSliderAcContainer = new QWidget(this); 374 | const auto backlightSliderAcLayout = new QHBoxLayout(backlightSliderAcContainer); 375 | backlightSliderAcContainer->setContentsMargins(0, 0, 0, 0); 376 | backlightSliderAcLayout->setMargin(0); 377 | 378 | backlightSliderAcLayout->addWidget(backlightACCheck); 379 | backlightSliderAcLayout->addWidget(backlightSliderAC); 380 | 381 | const auto acBacklightOptContainer = new QWidget(this); 382 | const auto acBacklightOptContainerLayout = new QVBoxLayout(acBacklightOptContainer); 383 | 384 | acBacklightOptContainer->setContentsMargins(0, 0, 0, 0); 385 | acBacklightOptContainer->setMaximumWidth(MAX_WIDTH); 386 | acBacklightOptContainer->setMinimumWidth(MAX_WIDTH); 387 | acBacklightOptContainerLayout->setMargin(0); 388 | acBacklightOptContainerLayout->setContentsMargins(0, 0, 0, 0); 389 | acBacklightOptContainerLayout->addWidget(backlightSliderAcContainer); 390 | acBacklightOptContainerLayout->addWidget(backlightACHigherCheck); 391 | 392 | const auto acBacklightContainer = new QWidget(this); 393 | const auto acBacklightContainerLayout = new QHBoxLayout(acBacklightContainer); 394 | acBacklightContainerLayout->setMargin(0); 395 | 396 | acBacklightLabel = new QLabel(this); 397 | 398 | acBacklightLabel->setText(tr("Brightness")); 399 | acBacklightLabel->setToolTip(tr("Override brightness when switched to AC power.")); 400 | acBacklightContainerLayout->addWidget(acBacklightLabel); 401 | acBacklightContainerLayout->addStretch(); 402 | acBacklightContainerLayout->addWidget(acBacklightOptContainer); 403 | 404 | // add widgets to ac 405 | acContainerLayout->addSpacing(10); 406 | acContainerLayout->addWidget(sleepACContainer); 407 | acContainerLayout->addSpacing(10); 408 | acContainerLayout->addStretch(); 409 | acContainerLayout->addWidget(acBacklightContainer); 410 | 411 | // common 412 | const auto daemonContainer = new QGroupBox(this); 413 | daemonContainer->setTitle(tr("Options")); 414 | const auto daemonContainerLayout = new QVBoxLayout(daemonContainer); 415 | 416 | showSystemTray = new QCheckBox(this); 417 | showSystemTray->setText(tr("Show system tray")); 418 | showSystemTray->setToolTip(tr("Enable/Disable the system tray icon." 419 | " Note that notifications will not work when the systemtray is disabled.")); 420 | 421 | disableLidAction = new QCheckBox(this); 422 | disableLidAction->setText(tr("Disable lid action if external monitor connected")); 423 | disableLidAction->setToolTip(tr("Disable lid action if an external monitor is connected" 424 | " to your laptop.")); 425 | 426 | backlightMouseWheel = new QCheckBox(this); 427 | backlightMouseWheel->setText(tr("Adjust brightness in system tray")); 428 | backlightMouseWheel->setToolTip(tr("Adjust the display backlight brightness with the mouse wheel on the system tray icon.")); 429 | 430 | daemonContainerLayout->addWidget(showSystemTray); 431 | daemonContainerLayout->addWidget(backlightMouseWheel); 432 | daemonContainerLayout->addWidget(disableLidAction); 433 | daemonContainerLayout->addStretch(); 434 | 435 | // screensaver 436 | const auto ssContainer = new QWidget(this); 437 | const auto ssContainerLayout = new QHBoxLayout(ssContainer); 438 | ssContainerLayout->setMargin(0); 439 | 440 | const auto screensaverBlankLabel = new QLabel(tr("Screen Saver Timeout"), this); 441 | screensaverBlank = new QSpinBox(this); 442 | screensaverBlank->setMaximumWidth(MAX_WIDTH); 443 | screensaverBlank->setMinimumWidth(MAX_WIDTH); 444 | screensaverBlank->setMinimum(1); 445 | screensaverBlank->setMaximum(1000); 446 | screensaverBlank->setSuffix(QString(" %1").arg(tr("min"))); 447 | screensaverBlank->setPrefix(tr("After ")); 448 | 449 | ssContainerLayout->addWidget(screensaverBlankLabel); 450 | ssContainerLayout->addWidget(screensaverBlank); 451 | 452 | // notify 453 | const auto notifyContainer = new QGroupBox(this); 454 | notifyContainer->setTitle(tr("Notifications")); 455 | const auto notifyContainerLayout = new QVBoxLayout(notifyContainer); 456 | 457 | showNotifications = new QCheckBox(this); 458 | showNotifications->setText(tr("Show notifications")); 459 | showNotifications->setToolTip(tr("Show notifications for power related events.")); 460 | 461 | warnOnLowBattery = new QCheckBox(this); 462 | warnOnLowBattery->setText(tr("Notify on low battery")); 463 | warnOnLowBattery->setToolTip(tr("Show a notification when on low battery (%1% over critical)") 464 | .arg(POWERKIT_LOW_BATTERY)); 465 | 466 | warnOnVeryLowBattery = new QCheckBox(this); 467 | warnOnVeryLowBattery->setText(tr("Notify on very low battery")); 468 | warnOnVeryLowBattery->setToolTip(tr("Show a notification when on very low battery (1% over critical)")); 469 | 470 | notifyOnBattery = new QCheckBox(this); 471 | notifyOnBattery->setText(tr("Notify on battery")); 472 | notifyOnBattery->setToolTip(tr("Notify when switched on battery power")); 473 | 474 | notifyOnAC = new QCheckBox(this); 475 | notifyOnAC->setText(tr("Notify on AC")); 476 | notifyOnAC->setToolTip(tr("Notify when switched on AC power")); 477 | 478 | notifyNewInhibitor = new QCheckBox(this); 479 | notifyNewInhibitor->setText(tr("Notify on new inhibitors")); 480 | notifyNewInhibitor->setToolTip(tr("Notify on new screensaver or power inhibitors")); 481 | 482 | notifyContainerLayout->addWidget(showNotifications); 483 | notifyContainerLayout->addWidget(warnOnLowBattery); 484 | notifyContainerLayout->addWidget(warnOnVeryLowBattery); 485 | notifyContainerLayout->addWidget(notifyOnBattery); 486 | notifyContainerLayout->addWidget(notifyOnAC); 487 | notifyContainerLayout->addWidget(notifyNewInhibitor); 488 | notifyContainerLayout->addStretch(); 489 | 490 | const auto commonWidget = new QWidget(this); 491 | const auto commonWidgetLayout = new QVBoxLayout(commonWidget); 492 | 493 | const auto optContainer = new QWidget(this); 494 | const auto optContainerLayout = new QHBoxLayout(optContainer); 495 | optContainerLayout->setMargin(0); 496 | 497 | const auto batteryAcContainer = new QWidget(this); 498 | const auto batteryAcContainerLayout = new QHBoxLayout(batteryAcContainer); 499 | batteryAcContainerLayout->setMargin(0); 500 | 501 | batteryAcContainerLayout->addWidget(batteryContainer); 502 | batteryAcContainerLayout->addWidget(acContainer); 503 | 504 | optContainerLayout->addWidget(daemonContainer); 505 | optContainerLayout->addWidget(notifyContainer); 506 | 507 | commonWidgetLayout->addWidget(batteryAcContainer); 508 | commonWidgetLayout->addWidget(optContainer); 509 | commonWidgetLayout->addWidget(ssContainer); 510 | 511 | const auto scrollArea = new QScrollArea(this); 512 | scrollArea->setSizePolicy(QSizePolicy::Expanding, 513 | QSizePolicy::Expanding); 514 | scrollArea->setWidgetResizable(true); 515 | scrollArea->setStyleSheet("QScrollArea { border: 0; }"); 516 | scrollArea->setWidget(commonWidget); 517 | 518 | layout->addWidget(statusWidget); 519 | layout->addWidget(scrollArea); 520 | 521 | handleUpdatedDevices(); 522 | } 523 | 524 | // populate widgets with default values 525 | void Dialog::populateWidgets() 526 | { 527 | lidActionBattery->clear(); 528 | lidActionBattery->addItem(tr("None"), lidNone); 529 | lidActionBattery->addItem(tr("Lock Screen"), lidLock); 530 | lidActionBattery->addItem(tr("Sleep"), lidSleep); 531 | lidActionBattery->addItem(tr("Hibernate"), lidHibernate); 532 | lidActionBattery->addItem(tr("Shutdown"), lidShutdown); 533 | lidActionBattery->addItem(tr("Hybrid Sleep"), lidHybridSleep); 534 | lidActionBattery->addItem(tr("Sleep then Hibernate"), lidSleepHibernate); 535 | 536 | lidActionAC->clear(); 537 | lidActionAC->addItem(tr("None"), lidNone); 538 | lidActionAC->addItem(tr("Lock Screen"), lidLock); 539 | lidActionAC->addItem(tr("Sleep"), lidSleep); 540 | lidActionAC->addItem(tr("Hibernate"), lidHibernate); 541 | lidActionAC->addItem(tr("Shutdown"), lidShutdown); 542 | lidActionAC->addItem(tr("Hybrid Sleep"), lidHybridSleep); 543 | lidActionAC->addItem(tr("Sleep then Hibernate"), lidSleepHibernate); 544 | 545 | criticalActionBattery->clear(); 546 | criticalActionBattery->addItem(tr("None"), criticalNone); 547 | criticalActionBattery->addItem(tr("Sleep"), criticalSuspend); 548 | criticalActionBattery->addItem(tr("Hibernate"), criticalHibernate); 549 | criticalActionBattery->addItem(tr("Shutdown"), criticalShutdown); 550 | 551 | autoSleepBatteryAction->clear(); 552 | autoSleepBatteryAction->addItem(tr("None"), suspendNone); 553 | autoSleepBatteryAction->addItem(tr("Sleep"), suspendSleep); 554 | autoSleepBatteryAction->addItem(tr("Hibernate"), suspendHibernate); 555 | autoSleepBatteryAction->addItem(tr("Shutdown"), suspendShutdown); 556 | autoSleepBatteryAction->addItem(tr("Hybrid Sleep"), suspendHybrid); 557 | autoSleepBatteryAction->addItem(tr("Sleep then Hibernate"), suspendSleepHibernate); 558 | 559 | autoSleepACAction->clear(); 560 | autoSleepACAction->addItem(tr("None"), suspendNone); 561 | autoSleepACAction->addItem(tr("Sleep"), suspendSleep); 562 | autoSleepACAction->addItem(tr("Hibernate"), suspendHibernate); 563 | autoSleepACAction->addItem(tr("Shutdown"), suspendShutdown); 564 | autoSleepACAction->addItem(tr("Hybrid Sleep"), suspendHybrid); 565 | autoSleepACAction->addItem(tr("Sleep then Hibernate"), suspendSleepHibernate); 566 | } 567 | 568 | void Dialog::connectWidgets() 569 | { 570 | connect(lidActionBattery, SIGNAL(currentIndexChanged(int)), 571 | this, SLOT(handleLidActionBattery(int))); 572 | connect(lidActionAC, SIGNAL(currentIndexChanged(int)), 573 | this, SLOT(handleLidActionAC(int))); 574 | connect(criticalActionBattery, SIGNAL(currentIndexChanged(int)), 575 | this, SLOT(handleCriticalAction(int))); 576 | connect(criticalBattery, SIGNAL(valueChanged(int)), 577 | this, SLOT(handleCriticalBattery(int))); 578 | connect(autoSleepBattery, SIGNAL(valueChanged(int)), 579 | this, SLOT(handleAutoSleepBattery(int))); 580 | connect(autoSleepAC, SIGNAL(valueChanged(int)), 581 | this, SLOT(handleAutoSleepAC(int))); 582 | connect(showNotifications, SIGNAL(toggled(bool)), 583 | this, SLOT(handleShowNotifications(bool))); 584 | connect(showSystemTray, SIGNAL(toggled(bool)), 585 | this, SLOT(handleShowSystemTray(bool))); 586 | connect(disableLidAction, SIGNAL(toggled(bool)), 587 | this, SLOT(handleDisableLidAction(bool))); 588 | connect(autoSleepBatteryAction, SIGNAL(currentIndexChanged(int)), 589 | this, SLOT(handleAutoSleepBatteryAction(int))); 590 | connect(autoSleepACAction, SIGNAL(currentIndexChanged(int)), 591 | this, SLOT(handleAutoSleepACAction(int))); 592 | connect(backlightBatteryCheck, SIGNAL(toggled(bool)), 593 | this, SLOT(handleBacklightBatteryCheck(bool))); 594 | connect(backlightACCheck, SIGNAL(toggled(bool)), 595 | this, SLOT(handleBacklightACCheck(bool))); 596 | connect(backlightSliderBattery, SIGNAL(valueChanged(int)), 597 | this, SLOT(handleBacklightBatterySlider(int))); 598 | connect(backlightSliderAC, SIGNAL(valueChanged(int)), 599 | this, SLOT(handleBacklightACSlider(int))); 600 | connect(backlightBatteryLowerCheck, SIGNAL(toggled(bool)), 601 | this, SLOT(handleBacklightBatteryCheckLower(bool))); 602 | connect(backlightACHigherCheck, SIGNAL(toggled(bool)), 603 | this, SLOT(handleBacklightACCheckHigher(bool))); 604 | connect(warnOnLowBattery, SIGNAL(toggled(bool)), 605 | this, SLOT(handleWarnOnLowBattery(bool))); 606 | connect(warnOnVeryLowBattery, SIGNAL(toggled(bool)), 607 | this, SLOT(handleWarnOnVeryLowBattery(bool))); 608 | connect(notifyOnBattery, SIGNAL(toggled(bool)), 609 | this, SLOT(handleNotifyBattery(bool))); 610 | connect(notifyOnAC, SIGNAL(toggled(bool)), 611 | this, SLOT(handleNotifyAC(bool))); 612 | connect(notifyNewInhibitor, SIGNAL(toggled(bool)), 613 | this, SLOT(handleNotifyNewInhibitor(bool))); 614 | connect(backlightMouseWheel, SIGNAL(toggled(bool)), 615 | this, SLOT(handleBacklightMouseWheel(bool))); 616 | connect(screensaverBlank, SIGNAL(valueChanged(int)), 617 | this, SLOT(handleScreensaverBlank(int))); 618 | } 619 | 620 | // load settings and set defaults 621 | void Dialog::loadSettings() 622 | { 623 | if (Settings::isValid(CONF_DIALOG_GEOMETRY)) { 624 | restoreGeometry(Settings::getValue(CONF_DIALOG_GEOMETRY).toByteArray()); 625 | } 626 | 627 | int defaultAutoSleepBattery = POWERKIT_AUTO_SLEEP_BATTERY; 628 | if (Settings::isValid(CONF_SUSPEND_BATTERY_TIMEOUT)) { 629 | defaultAutoSleepBattery = Settings::getValue(CONF_SUSPEND_BATTERY_TIMEOUT).toInt(); 630 | } 631 | setDefaultAction(autoSleepBattery, defaultAutoSleepBattery); 632 | 633 | int defaultAutoSleepBatteryAction = POWERKIT_SUSPEND_BATTERY_ACTION; 634 | if (Settings::isValid(CONF_SUSPEND_BATTERY_ACTION)) { 635 | defaultAutoSleepBatteryAction = Settings::getValue(CONF_SUSPEND_BATTERY_ACTION).toInt(); 636 | } 637 | setDefaultAction(autoSleepBatteryAction, defaultAutoSleepBatteryAction); 638 | 639 | int defaultAutoSleepAC = 0; 640 | if (Settings::isValid(CONF_SUSPEND_AC_TIMEOUT)) { 641 | defaultAutoSleepAC = Settings::getValue(CONF_SUSPEND_AC_TIMEOUT).toInt(); 642 | } 643 | setDefaultAction(autoSleepAC, defaultAutoSleepAC); 644 | 645 | int defaultAutoSleepACAction = POWERKIT_SUSPEND_AC_ACTION; 646 | if (Settings::isValid(CONF_SUSPEND_AC_ACTION)) { 647 | defaultAutoSleepACAction = Settings::getValue(CONF_SUSPEND_AC_ACTION).toInt(); 648 | } 649 | setDefaultAction(autoSleepACAction, defaultAutoSleepACAction); 650 | 651 | int defaultCriticalBattery = POWERKIT_CRITICAL_BATTERY; 652 | if (Settings::isValid(CONF_CRITICAL_BATTERY_TIMEOUT)) { 653 | defaultCriticalBattery = Settings::getValue(CONF_CRITICAL_BATTERY_TIMEOUT).toInt(); 654 | } 655 | setDefaultAction(criticalBattery, defaultCriticalBattery); 656 | 657 | int defaultLidActionBattery = POWERKIT_LID_BATTERY_ACTION; 658 | if (Settings::isValid(CONF_LID_BATTERY_ACTION)) { 659 | defaultLidActionBattery = Settings::getValue(CONF_LID_BATTERY_ACTION).toInt(); 660 | } 661 | setDefaultAction(lidActionBattery, defaultLidActionBattery); 662 | 663 | int defaultLidActionAC = POWERKIT_LID_AC_ACTION; 664 | if (Settings::isValid(CONF_LID_AC_ACTION)) { 665 | defaultLidActionAC = Settings::getValue(CONF_LID_AC_ACTION).toInt(); 666 | } 667 | setDefaultAction(lidActionAC, defaultLidActionAC); 668 | 669 | int defaultCriticalAction = POWERKIT_CRITICAL_ACTION; 670 | if (Settings::isValid(CONF_CRITICAL_BATTERY_ACTION)) { 671 | defaultCriticalAction = Settings::getValue(CONF_CRITICAL_BATTERY_ACTION).toInt(); 672 | } 673 | setDefaultAction(criticalActionBattery, defaultCriticalAction); 674 | 675 | bool defaultShowNotifications = true; 676 | if (Settings::isValid(CONF_TRAY_NOTIFY)) { 677 | defaultShowNotifications = Settings::getValue(CONF_TRAY_NOTIFY).toBool(); 678 | } 679 | showNotifications->setChecked(defaultShowNotifications); 680 | 681 | bool defaultShowTray = true; 682 | if (Settings::isValid(CONF_TRAY_SHOW)) { 683 | defaultShowTray = Settings::getValue(CONF_TRAY_SHOW).toBool(); 684 | } 685 | showSystemTray->setChecked(defaultShowTray); 686 | 687 | bool defaultDisableLidAction = true; 688 | if (Settings::isValid(CONF_LID_DISABLE_IF_EXTERNAL)) { 689 | defaultDisableLidAction = Settings::getValue(CONF_LID_DISABLE_IF_EXTERNAL).toBool(); 690 | } 691 | disableLidAction->setChecked(defaultDisableLidAction); 692 | 693 | bool defaultWarnOnLowBattery = true; 694 | if (Settings::isValid(CONF_WARN_ON_LOW_BATTERY)) { 695 | defaultWarnOnLowBattery = Settings::getValue(CONF_WARN_ON_LOW_BATTERY).toBool(); 696 | } 697 | warnOnLowBattery->setChecked(defaultWarnOnLowBattery); 698 | 699 | bool defaultWarnOnVeryLowBattery = true; 700 | if (Settings::isValid(CONF_WARN_ON_VERYLOW_BATTERY)) { 701 | defaultWarnOnVeryLowBattery = Settings::getValue(CONF_WARN_ON_VERYLOW_BATTERY).toBool(); 702 | } 703 | warnOnVeryLowBattery->setChecked(defaultWarnOnVeryLowBattery); 704 | 705 | bool defaultNotifyOnBattery = true; 706 | if (Settings::isValid(CONF_NOTIFY_ON_BATTERY)) { 707 | defaultNotifyOnBattery = Settings::getValue(CONF_NOTIFY_ON_BATTERY).toBool(); 708 | } 709 | notifyOnBattery->setChecked(defaultNotifyOnBattery); 710 | 711 | bool defaultNotifyOnAC = true; 712 | if (Settings::isValid(CONF_NOTIFY_ON_AC)) { 713 | defaultNotifyOnAC = Settings::getValue(CONF_NOTIFY_ON_AC).toBool(); 714 | } 715 | notifyOnAC->setChecked(defaultNotifyOnAC); 716 | 717 | bool defaultNotifyNewInhibitor = true; 718 | if (Settings::isValid(CONF_NOTIFY_NEW_INHIBITOR)) { 719 | defaultNotifyNewInhibitor = Settings::getValue(CONF_NOTIFY_NEW_INHIBITOR).toBool(); 720 | } 721 | notifyNewInhibitor->setChecked(defaultNotifyNewInhibitor); 722 | 723 | // check 724 | checkPerms(); 725 | 726 | // backlight 727 | backlightDevice = Backlight::getDevice(); 728 | 729 | backlightSliderAC->setEnabled(true); 730 | backlightSliderBattery->setEnabled(true); 731 | 732 | int backlightMin = 1; 733 | int backlightMax = Backlight::getMaxBrightness(backlightDevice); 734 | 735 | backlightSliderBattery->setMinimum(backlightMin); 736 | backlightSliderBattery->setMaximum(backlightMax); 737 | backlightSliderBattery->setValue(backlightSliderBattery->maximum()); 738 | backlightSliderAC->setMinimum(backlightMin); 739 | backlightSliderAC->setMaximum(backlightMax); 740 | backlightSliderAC->setValue(backlightSliderAC->maximum()); 741 | 742 | backlightBatteryCheck->setChecked(Settings::getValue(CONF_BACKLIGHT_BATTERY_ENABLE) 743 | .toBool()); 744 | backlightACCheck->setChecked(Settings::getValue(CONF_BACKLIGHT_AC_ENABLE) 745 | .toBool()); 746 | if (Settings::isValid(CONF_BACKLIGHT_BATTERY)) { 747 | backlightSliderBattery->setValue(Settings::getValue(CONF_BACKLIGHT_BATTERY) 748 | .toInt()); 749 | } 750 | if (Settings::isValid(CONF_BACKLIGHT_AC)) { 751 | backlightSliderAC->setValue(Settings::getValue(CONF_BACKLIGHT_AC) 752 | .toInt()); 753 | } 754 | if (Settings::isValid(CONF_BACKLIGHT_BATTERY_DISABLE_IF_LOWER)) { 755 | backlightBatteryLowerCheck->setChecked( 756 | Settings::getValue(CONF_BACKLIGHT_BATTERY_DISABLE_IF_LOWER) 757 | .toBool()); 758 | } 759 | if (Settings::isValid(CONF_BACKLIGHT_AC_DISABLE_IF_HIGHER)) { 760 | backlightACHigherCheck->setChecked( 761 | Settings::getValue(CONF_BACKLIGHT_AC_DISABLE_IF_HIGHER) 762 | .toBool()); 763 | } 764 | bool defaultBacklightMouseWheel = true; 765 | if (Settings::isValid(CONF_BACKLIGHT_MOUSE_WHEEL)) { 766 | defaultBacklightMouseWheel = Settings::getValue(CONF_BACKLIGHT_MOUSE_WHEEL).toBool(); 767 | } 768 | backlightMouseWheel->setChecked(defaultBacklightMouseWheel); 769 | 770 | enableBacklight(true); 771 | enableLid(Client::lidIsPresent(dbus)); 772 | hasCpuCoreTemp = Cpu::hasCoreTemp(); 773 | if (!hasCpuCoreTemp) { cpuTempLabel->setVisible(false); } 774 | 775 | screensaverBlank->setValue(Settings::getValue(CONF_SCREENSAVER_TIMEOUT_BLANK, 776 | POWERKIT_SCREENSAVER_TIMEOUT_BLANK).toInt() / 60); 777 | } 778 | 779 | void Dialog::saveSettings() 780 | { 781 | Settings::setValue(CONF_LID_BATTERY_ACTION, 782 | lidActionBattery->currentData().toInt()); 783 | Settings::setValue(CONF_LID_AC_ACTION, 784 | lidActionAC->currentData().toInt()); 785 | Settings::setValue(CONF_CRITICAL_BATTERY_ACTION, 786 | criticalActionBattery->currentData().toInt()); 787 | Settings::setValue(CONF_CRITICAL_BATTERY_TIMEOUT, 788 | criticalBattery->value()); 789 | Settings::setValue(CONF_SUSPEND_BATTERY_TIMEOUT, 790 | autoSleepBattery->value()); 791 | Settings::setValue(CONF_SUSPEND_AC_TIMEOUT, 792 | autoSleepAC->value()); 793 | Settings::setValue(CONF_TRAY_NOTIFY, 794 | showNotifications->isChecked()); 795 | Settings::setValue(CONF_TRAY_SHOW, 796 | showSystemTray->isChecked()); 797 | Settings::setValue(CONF_LID_DISABLE_IF_EXTERNAL, 798 | disableLidAction->isChecked()); 799 | Settings::setValue(CONF_SUSPEND_BATTERY_ACTION, 800 | autoSleepBatteryAction->currentData().toInt()); 801 | Settings::setValue(CONF_SUSPEND_AC_ACTION, 802 | autoSleepACAction->currentData().toInt()); 803 | Settings::setValue(CONF_BACKLIGHT_BATTERY_ENABLE, 804 | backlightBatteryCheck->isChecked()); 805 | Settings::setValue(CONF_BACKLIGHT_AC_ENABLE, 806 | backlightACCheck->isChecked()); 807 | Settings::setValue(CONF_BACKLIGHT_BATTERY, 808 | backlightSliderBattery->value()); 809 | Settings::setValue(CONF_BACKLIGHT_AC, 810 | backlightSliderAC->value()); 811 | Settings::setValue(CONF_BACKLIGHT_BATTERY_DISABLE_IF_LOWER, 812 | backlightBatteryLowerCheck->isChecked()); 813 | Settings::setValue(CONF_BACKLIGHT_AC_DISABLE_IF_HIGHER, 814 | backlightACHigherCheck->isChecked()); 815 | Settings::setValue(CONF_DIALOG, 816 | saveGeometry()); 817 | Settings::setValue(CONF_WARN_ON_LOW_BATTERY, 818 | warnOnLowBattery->isChecked()); 819 | Settings::setValue(CONF_WARN_ON_VERYLOW_BATTERY, 820 | warnOnVeryLowBattery->isChecked()); 821 | Settings::setValue(CONF_NOTIFY_ON_BATTERY, 822 | notifyOnBattery->isChecked()); 823 | Settings::setValue(CONF_NOTIFY_ON_AC, 824 | notifyOnAC->isChecked()); 825 | Settings::setValue(CONF_NOTIFY_NEW_INHIBITOR, 826 | notifyNewInhibitor->isChecked()); 827 | Settings::setValue(CONF_BACKLIGHT_MOUSE_WHEEL, 828 | backlightMouseWheel->isChecked()); 829 | } 830 | 831 | // set default action in combobox 832 | void Dialog::setDefaultAction(QComboBox *box, int action) 833 | { 834 | for (int i=0;icount();i++) { 835 | if (box->itemData(i).toInt() == action) { 836 | box->setCurrentIndex(i); 837 | return; 838 | } 839 | } 840 | } 841 | 842 | // set default value in spinbox 843 | void Dialog::setDefaultAction(QSpinBox *box, int action) 844 | { 845 | box->setValue(action); 846 | } 847 | 848 | // set default value in combobox 849 | void Dialog::setDefaultAction(QComboBox *box, QString value) 850 | { 851 | for (int i=0;icount();i++) { 852 | if (box->itemText(i) == value) { 853 | box->setCurrentIndex(i); 854 | return; 855 | } 856 | } 857 | } 858 | 859 | void Dialog::drawBattery() 860 | { 861 | if (!hasBattery) { return; } 862 | const auto battery = Client::getBatteryLeft(dbus); 863 | const auto onBattery = Client::onBattery(dbus); 864 | QString batteryTime = QDateTime::fromTime_t(onBattery ? Client::timeToEmpty(dbus) : Client::timeToFull(dbus)).toUTC().toString("hh:mm"); 865 | QColor colorBg = Qt::green; 866 | QColor colorFg = Qt::white; 867 | QString status = QString("%1%\n%2").arg(QString::number(battery), batteryTime); 868 | if (onBattery) { 869 | if (battery >= 26) { 870 | colorBg = QColor("orange"); 871 | } else { 872 | colorBg = Qt::red; 873 | } 874 | } else { 875 | if (battery == 100) { 876 | colorFg = Qt::green; 877 | status = QString("%1%").arg(QString::number(battery)); 878 | } 879 | } 880 | batteryStatusLabel->setPixmap(Theme::drawCircleProgress(battery, 881 | 64, 882 | 4, 883 | 4, 884 | true, 885 | status, 886 | colorBg, 887 | colorFg)); 888 | } 889 | 890 | void Dialog::drawCpu() 891 | { 892 | if (cpuFreqLabel) { 893 | const auto freq = Cpu::getCpuFreqLabel(); 894 | QColor color = Qt::gray; 895 | if (freq.first >= 50) { color = QColor("orange"); } 896 | cpuFreqLabel->setPixmap(Theme::drawCircleProgress(freq.first, 897 | 64, 898 | 4, 899 | 4, 900 | true, 901 | freq.second, 902 | color, 903 | Qt::white)); 904 | } 905 | if (cpuTempLabel && hasCpuCoreTemp) { 906 | const auto temp = Cpu::getCpuTempLabel(); 907 | QColor color = Qt::gray; 908 | if (temp.first >= 75) { color = Qt::red; } 909 | else if (temp.first >= 50) { color = QColor("orange"); } 910 | cpuTempLabel->setPixmap(Theme::drawCircleProgress(temp.first, 911 | 64, 912 | 4, 913 | 4, 914 | true, 915 | temp.second, 916 | color, 917 | Qt::white)); 918 | } 919 | } 920 | 921 | void Dialog::handleUpdatedDevices() 922 | { 923 | hasBattery = Client::hasBattery(dbus); 924 | batteryStatusLabel->setVisible(hasBattery); 925 | drawBattery(); 926 | drawCpu(); 927 | } 928 | 929 | // save current value and update power manager 930 | void Dialog::handleLidActionBattery(int index) 931 | { 932 | checkPerms(); 933 | Settings::setValue(CONF_LID_BATTERY_ACTION, 934 | lidActionBattery->itemData(index).toInt()); 935 | } 936 | 937 | void Dialog::handleLidActionAC(int index) 938 | { 939 | checkPerms(); 940 | Settings::setValue(CONF_LID_AC_ACTION, 941 | lidActionAC->itemData(index).toInt()); 942 | } 943 | 944 | void Dialog::handleCriticalAction(int index) 945 | { 946 | checkPerms(); 947 | Settings::setValue(CONF_CRITICAL_BATTERY_ACTION, 948 | criticalActionBattery->itemData(index).toInt()); 949 | } 950 | 951 | void Dialog::handleCriticalBattery(int value) 952 | { 953 | Settings::setValue(CONF_CRITICAL_BATTERY_TIMEOUT, value); 954 | } 955 | 956 | void Dialog::handleAutoSleepBattery(int value) 957 | { 958 | Settings::setValue(CONF_SUSPEND_BATTERY_TIMEOUT, value); 959 | } 960 | 961 | void Dialog::handleAutoSleepAC(int value) 962 | { 963 | Settings::setValue(CONF_SUSPEND_AC_TIMEOUT, value); 964 | } 965 | 966 | void Dialog::handleShowNotifications(bool triggered) 967 | { 968 | Settings::setValue(CONF_TRAY_NOTIFY, triggered); 969 | } 970 | 971 | void Dialog::handleShowSystemTray(bool triggered) 972 | { 973 | Settings::setValue(CONF_TRAY_SHOW, triggered); 974 | } 975 | 976 | void Dialog::handleDisableLidAction(bool triggered) 977 | { 978 | Settings::setValue(CONF_LID_DISABLE_IF_EXTERNAL, triggered); 979 | } 980 | 981 | void Dialog::handleAutoSleepBatteryAction(int index) 982 | { 983 | checkPerms(); 984 | Settings::setValue(CONF_SUSPEND_BATTERY_ACTION, 985 | autoSleepBatteryAction->itemData(index).toInt()); 986 | } 987 | 988 | void Dialog::handleAutoSleepACAction(int index) 989 | { 990 | checkPerms(); 991 | Settings::setValue(CONF_SUSPEND_AC_ACTION, 992 | autoSleepACAction->itemData(index).toInt()); 993 | } 994 | 995 | void Dialog::checkPerms() 996 | { 997 | if (!Client::canHibernate(dbus)) { 998 | bool warnCantHibernate = false; 999 | if (criticalActionBattery->currentData().toInt() == criticalHibernate) { 1000 | warnCantHibernate = true; 1001 | criticalActionBattery->setCurrentIndex(criticalShutdown); 1002 | handleCriticalAction(criticalShutdown); 1003 | } 1004 | if (lidActionAC->currentData().toInt() == lidHibernate || 1005 | lidActionAC->currentData().toInt() == lidHybridSleep) { 1006 | warnCantHibernate = true; 1007 | lidActionAC->setCurrentIndex(lidSleep); 1008 | handleLidActionAC(lidSleep); 1009 | } 1010 | if (lidActionBattery->currentData().toInt() == lidHibernate || 1011 | lidActionBattery->currentData().toInt() == lidHybridSleep) { 1012 | warnCantHibernate = true; 1013 | lidActionBattery->setCurrentIndex(lidSleep); 1014 | handleLidActionBattery(lidSleep); 1015 | } 1016 | if (autoSleepACAction->currentData().toInt() == suspendHibernate || 1017 | autoSleepACAction->currentData().toInt() == suspendHybrid) { 1018 | warnCantHibernate = true; 1019 | autoSleepACAction->setCurrentIndex(suspendSleep); 1020 | handleAutoSleepACAction(suspendSleep); 1021 | } 1022 | if (autoSleepBatteryAction->currentData().toInt() == suspendHibernate || 1023 | autoSleepBatteryAction->currentData().toInt() == suspendHybrid) { 1024 | warnCantHibernate = true; 1025 | autoSleepBatteryAction->setCurrentIndex(suspendSleep); 1026 | handleAutoSleepBatteryAction(suspendSleep); 1027 | } 1028 | if (warnCantHibernate) { hibernateWarn(); } 1029 | } 1030 | if (!Client::canSuspend(dbus)) { 1031 | bool warnCantSleep = false; 1032 | if (lidActionAC->currentData().toInt() == lidSleep) { 1033 | warnCantSleep = true; 1034 | lidActionAC->setCurrentIndex(lidLock); 1035 | handleLidActionAC(lidLock); 1036 | } 1037 | if (lidActionBattery->currentData().toInt() == lidSleep) { 1038 | warnCantSleep = true; 1039 | lidActionBattery->setCurrentIndex(lidLock); 1040 | handleLidActionBattery(lidLock); 1041 | } 1042 | if (autoSleepACAction->currentData().toInt() == suspendSleep) { 1043 | warnCantSleep = true; 1044 | autoSleepACAction->setCurrentIndex(suspendNone); 1045 | handleAutoSleepACAction(suspendNone); 1046 | } 1047 | if (autoSleepBatteryAction->currentData().toInt() == suspendSleep) { 1048 | warnCantSleep = true; 1049 | autoSleepBatteryAction->setCurrentIndex(suspendNone); 1050 | handleAutoSleepBatteryAction(suspendNone); 1051 | } 1052 | if (warnCantSleep) { sleepWarn(); } 1053 | } 1054 | } 1055 | 1056 | void Dialog::handleBacklightBatteryCheck(bool triggered) 1057 | { 1058 | Settings::setValue(CONF_BACKLIGHT_BATTERY_ENABLE, triggered); 1059 | } 1060 | 1061 | void Dialog::handleBacklightACCheck(bool triggered) 1062 | { 1063 | Settings::setValue(CONF_BACKLIGHT_AC_ENABLE, triggered); 1064 | } 1065 | 1066 | void Dialog::handleBacklightBatterySlider(int value) 1067 | { 1068 | Settings::setValue(CONF_BACKLIGHT_BATTERY, value); 1069 | } 1070 | 1071 | void Dialog::handleBacklightACSlider(int value) 1072 | { 1073 | Settings::setValue(CONF_BACKLIGHT_AC, value); 1074 | } 1075 | 1076 | void Dialog::hibernateWarn() 1077 | { 1078 | QMessageBox::warning(this, tr("Hibernate not supported"), 1079 | tr("Hibernate not supported, consult your OS documentation.")); 1080 | } 1081 | 1082 | void Dialog::sleepWarn() 1083 | { 1084 | QMessageBox::warning(this, tr("Sleep not supported"), 1085 | tr("Sleep not supported, consult your OS documentation.")); 1086 | } 1087 | 1088 | void Dialog::handleBacklightBatteryCheckLower(bool triggered) 1089 | { 1090 | Settings::setValue(CONF_BACKLIGHT_BATTERY_DISABLE_IF_LOWER, triggered); 1091 | } 1092 | 1093 | void Dialog::handleBacklightACCheckHigher(bool triggered) 1094 | { 1095 | Settings::setValue(CONF_BACKLIGHT_AC_DISABLE_IF_HIGHER, triggered); 1096 | } 1097 | 1098 | void Dialog::enableBacklight(bool enabled) 1099 | { 1100 | backlightSliderBattery->setEnabled(enabled); 1101 | backlightSliderAC->setEnabled(enabled); 1102 | backlightBatteryCheck->setEnabled(enabled); 1103 | backlightACCheck->setEnabled(enabled); 1104 | backlightBatteryLowerCheck->setEnabled(enabled); 1105 | backlightACHigherCheck->setEnabled(enabled); 1106 | batteryBacklightLabel->setEnabled(enabled); 1107 | acBacklightLabel->setEnabled(enabled); 1108 | backlightMouseWheel->setEnabled(enabled); 1109 | } 1110 | 1111 | void Dialog::handleWarnOnLowBattery(bool triggered) 1112 | { 1113 | Settings::setValue(CONF_WARN_ON_LOW_BATTERY, triggered); 1114 | } 1115 | 1116 | void Dialog::handleWarnOnVeryLowBattery(bool triggered) 1117 | { 1118 | Settings::setValue(CONF_WARN_ON_VERYLOW_BATTERY, triggered); 1119 | } 1120 | 1121 | void Dialog::handleNotifyBattery(bool triggered) 1122 | { 1123 | Settings::setValue(CONF_NOTIFY_ON_BATTERY, triggered); 1124 | } 1125 | 1126 | void Dialog::handleNotifyAC(bool triggered) 1127 | { 1128 | Settings::setValue(CONF_NOTIFY_ON_AC, triggered); 1129 | } 1130 | 1131 | void Dialog::handleNotifyNewInhibitor(bool triggered) 1132 | { 1133 | Settings::setValue(CONF_NOTIFY_NEW_INHIBITOR, triggered); 1134 | } 1135 | 1136 | void Dialog::enableLid(bool enabled) 1137 | { 1138 | lidActionAC->setEnabled(enabled); 1139 | lidActionBattery->setEnabled(enabled); 1140 | lidActionACLabel->setEnabled(enabled); 1141 | lidActionBatteryLabel->setEnabled(enabled); 1142 | disableLidAction->setEnabled(enabled); 1143 | } 1144 | 1145 | void Dialog::handleBacklightMouseWheel(bool triggered) 1146 | { 1147 | Settings::setValue(CONF_BACKLIGHT_MOUSE_WHEEL, triggered); 1148 | } 1149 | 1150 | void Dialog::handleScreensaverBlank(int value) 1151 | { 1152 | Settings::setValue(CONF_SCREENSAVER_TIMEOUT_BLANK, value * 60); 1153 | } 1154 | -------------------------------------------------------------------------------- /src/powerkit_dialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_CONFIG_H 10 | #define POWERKIT_CONFIG_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace PowerKit 33 | { 34 | class Dialog : public QDialog 35 | { 36 | Q_OBJECT 37 | 38 | public: 39 | explicit Dialog(QWidget *parent = nullptr, 40 | bool quitOnClose = true); 41 | ~Dialog(); 42 | 43 | private: 44 | QTimer *cpuTimer; 45 | QDBusInterface *dbus; 46 | QComboBox *lidActionBattery; 47 | QComboBox *lidActionAC; 48 | QComboBox *criticalActionBattery; 49 | QSpinBox *criticalBattery; 50 | QSpinBox *autoSleepBattery; 51 | QSpinBox *autoSleepAC; 52 | QCheckBox *showNotifications; 53 | QCheckBox *showSystemTray; 54 | QCheckBox *disableLidAction; 55 | QComboBox *autoSleepBatteryAction; 56 | QComboBox *autoSleepACAction; 57 | QString backlightDevice; 58 | QSlider *backlightSliderBattery; 59 | QSlider *backlightSliderAC; 60 | QCheckBox *backlightBatteryCheck; 61 | QCheckBox *backlightACCheck; 62 | QCheckBox *backlightBatteryLowerCheck; 63 | QCheckBox *backlightACHigherCheck; 64 | QCheckBox *warnOnLowBattery; 65 | QCheckBox *warnOnVeryLowBattery; 66 | 67 | QCheckBox *notifyOnBattery; 68 | QCheckBox *notifyOnAC; 69 | QCheckBox *notifyNewInhibitor; 70 | QLabel *lidActionACLabel; 71 | QLabel *lidActionBatteryLabel; 72 | QLabel *batteryBacklightLabel; 73 | QLabel *acBacklightLabel; 74 | QCheckBox *backlightMouseWheel; 75 | 76 | QLabel *batteryStatusLabel; 77 | QLabel *cpuFreqLabel; 78 | QLabel *cpuTempLabel; 79 | 80 | QSpinBox *screensaverBlank; 81 | 82 | bool hasCpuCoreTemp; 83 | bool hasBattery; 84 | 85 | private slots: 86 | void setupWidgets(); 87 | void populateWidgets(); 88 | void connectWidgets(); 89 | void loadSettings(); 90 | void saveSettings(); 91 | 92 | void setDefaultAction(QComboBox *box, int action); 93 | void setDefaultAction(QSpinBox *box, int action); 94 | void setDefaultAction(QComboBox *box, QString value); 95 | 96 | void drawBattery(); 97 | void drawCpu(); 98 | 99 | void handleUpdatedDevices(); 100 | 101 | void handleLidActionBattery(int index); 102 | void handleLidActionAC(int index); 103 | void handleCriticalAction(int index); 104 | void handleCriticalBattery(int value); 105 | void handleAutoSleepBattery(int value); 106 | void handleAutoSleepAC(int value); 107 | void handleShowNotifications(bool triggered); 108 | void handleShowSystemTray(bool triggered); 109 | void handleDisableLidAction(bool triggered); 110 | void handleAutoSleepBatteryAction(int index); 111 | void handleAutoSleepACAction(int index); 112 | void checkPerms(); 113 | void handleBacklightBatteryCheck(bool triggered); 114 | void handleBacklightACCheck(bool triggered); 115 | void handleBacklightBatterySlider(int value); 116 | void handleBacklightACSlider(int value); 117 | void hibernateWarn(); 118 | void sleepWarn(); 119 | void handleBacklightBatteryCheckLower(bool triggered); 120 | void handleBacklightACCheckHigher(bool triggered); 121 | void enableBacklight(bool enabled); 122 | void handleWarnOnLowBattery(bool triggered); 123 | void handleWarnOnVeryLowBattery(bool triggered); 124 | void handleNotifyBattery(bool triggered); 125 | void handleNotifyAC(bool triggered); 126 | void handleNotifyNewInhibitor(bool triggered); 127 | void enableLid(bool enabled); 128 | void handleBacklightMouseWheel(bool triggered); 129 | void handleScreensaverBlank(int value); 130 | }; 131 | } 132 | 133 | #endif // POWERKIT_CONFIG_H 134 | -------------------------------------------------------------------------------- /src/powerkit_manager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include "powerkit_manager.h" 10 | #include "powerkit_common.h" 11 | #include "powerkit_settings.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #define LOGIND_PATH "/org/freedesktop/login1" 23 | #define LOGIND_MANAGER "org.freedesktop.login1.Manager" 24 | #define LOGIND_DOCKED "Docked" 25 | 26 | #define UPOWER_PATH "/org/freedesktop/UPower" 27 | #define UPOWER_MANAGER "org.freedesktop.UPower" 28 | #define UPOWER_DEVICES "/org/freedesktop/UPower/devices/" 29 | #define UPOWER_DOCKED "IsDocked" 30 | #define UPOWER_LID_IS_PRESENT "LidIsPresent" 31 | #define UPOWER_LID_IS_CLOSED "LidIsClosed" 32 | #define UPOWER_ON_BATTERY "OnBattery" 33 | #define UPOWER_NOTIFY_RESUME "NotifyResume" 34 | #define UPOWER_NOTIFY_SLEEP "NotifySleep" 35 | 36 | #define DBUS_OK_REPLY "yes" 37 | #define DBUS_FAILED_CONN "Failed D-Bus connection." 38 | #define DBUS_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager" 39 | 40 | #define DBUS_INTROSPECTABLE "org.freedesktop.DBus.Introspectable" 41 | #define DBUS_JOBS "%1/jobs" 42 | #define DBUS_DEVICE_ADDED "DeviceAdded" 43 | #define DBUS_DEVICE_REMOVED "DeviceRemoved" 44 | #define DBUS_DEVICE_CHANGED "DeviceChanged" 45 | #define DBUS_PROPERTIES_CHANGED "PropertiesChanged" 46 | 47 | #define PK_PREPARE_FOR_SUSPEND "PrepareForSuspend" 48 | #define PK_PREPARE_FOR_SLEEP "PrepareForSleep" 49 | #define PK_CAN_RESTART "CanReboot" 50 | #define PK_RESTART "Reboot" 51 | #define PK_CAN_POWEROFF "CanPowerOff" 52 | #define PK_POWEROFF "PowerOff" 53 | #define PK_CAN_SUSPEND "CanSuspend" 54 | #define PK_SUSPEND_ALLOWED "SuspendAllowed" 55 | #define PK_SUSPEND "Suspend" 56 | #define PK_CAN_HIBERNATE "CanHibernate" 57 | #define PK_HIBERNATE_ALLOWED "HibernateAllowed" 58 | #define PK_HIBERNATE "Hibernate" 59 | #define PK_CAN_HYBRIDSLEEP "CanHybridSleep" 60 | #define PK_HYBRIDSLEEP "HybridSleep" 61 | #define PK_CAN_SUSPEND_THEN_HIBERNATE "CanSuspendThenHibernate" 62 | #define PK_SUSPEND_THEN_HIBERNATE "SuspendThenHibernate" 63 | #define PK_NO_BACKEND "No backend available." 64 | #define PK_NO_ACTION "Action no available." 65 | 66 | #define TIMEOUT_CHECK 60000 67 | 68 | using namespace PowerKit; 69 | 70 | Manager::Manager(QObject *parent) : QObject(parent) 71 | , upower(nullptr) 72 | , logind(nullptr) 73 | , wasDocked(false) 74 | , wasLidClosed(false) 75 | , wasOnBattery(false) 76 | { 77 | setup(); 78 | timer.setInterval(TIMEOUT_CHECK); 79 | connect(&timer, SIGNAL(timeout()), 80 | this, SLOT(check())); 81 | timer.start(); 82 | } 83 | 84 | Manager::~Manager() 85 | { 86 | clearDevices(); 87 | ReleaseSuspendLock(); 88 | } 89 | 90 | QMap Manager::getDevices() 91 | { 92 | return devices; 93 | } 94 | 95 | bool Manager::canLogind(const QString &method) 96 | { 97 | if (!logind->isValid() || method.isEmpty()) { return false; } 98 | QDBusMessage reply = logind->call(method); 99 | const auto args = reply.arguments(); 100 | if (args.first().toString() == DBUS_OK_REPLY) { return true; } 101 | bool result = args.first().toBool(); 102 | if (!reply.errorMessage().isEmpty()) { 103 | result = false; 104 | emit Warning(reply.errorMessage()); 105 | } 106 | return result; 107 | } 108 | 109 | const QDBusMessage Manager::callLogind(const QString &method) 110 | { 111 | QDBusMessage reply; 112 | if (logind->isValid() && !method.isEmpty()) { 113 | reply = logind->call(method, true); 114 | } 115 | return reply; 116 | } 117 | 118 | QStringList Manager::find() 119 | { 120 | QStringList result; 121 | QDBusMessage call = QDBusMessage::createMethodCall(POWERKIT_UPOWER_SERVICE, 122 | QString("%1/devices").arg(UPOWER_PATH), 123 | DBUS_INTROSPECTABLE, 124 | "Introspect"); 125 | QDBusPendingReply reply = QDBusConnection::systemBus().call(call); 126 | if (reply.isError()) { 127 | emit Warning(tr("Find devices failed, check the upower service!")); 128 | return result; 129 | } 130 | QList objects; 131 | QXmlStreamReader xml(reply.value()); 132 | if (xml.hasError()) { return result; } 133 | while (!xml.atEnd()) { 134 | xml.readNext(); 135 | if (xml.tokenType() == QXmlStreamReader::StartElement && 136 | xml.name().toString() == "node" ) { 137 | QString name = xml.attributes().value("name").toString(); 138 | if (!name.isEmpty()) { objects << QDBusObjectPath(UPOWER_DEVICES + name); } 139 | } 140 | } 141 | foreach (QDBusObjectPath device, objects) { 142 | result << device.path(); 143 | } 144 | return result; 145 | } 146 | 147 | void Manager::setup() 148 | { 149 | QDBusConnection system = QDBusConnection::systemBus(); 150 | if (!system.isConnected()) { 151 | emit Error(tr("Failed to connect to the system bus")); 152 | return; 153 | } 154 | 155 | system.connect(POWERKIT_UPOWER_SERVICE, 156 | UPOWER_PATH, 157 | POWERKIT_UPOWER_SERVICE, 158 | DBUS_DEVICE_ADDED, 159 | this, 160 | SLOT(deviceAdded(QDBusObjectPath))); 161 | system.connect(POWERKIT_UPOWER_SERVICE, 162 | UPOWER_PATH, 163 | POWERKIT_UPOWER_SERVICE, 164 | DBUS_DEVICE_ADDED, 165 | this, 166 | SLOT(deviceAdded(QString))); 167 | system.connect(POWERKIT_UPOWER_SERVICE, 168 | UPOWER_PATH, 169 | POWERKIT_UPOWER_SERVICE, 170 | DBUS_DEVICE_REMOVED, 171 | this, 172 | SLOT(deviceRemoved(QDBusObjectPath))); 173 | system.connect(POWERKIT_UPOWER_SERVICE, 174 | UPOWER_PATH, 175 | POWERKIT_UPOWER_SERVICE, 176 | DBUS_DEVICE_REMOVED, 177 | this, 178 | SLOT(deviceRemoved(QString))); 179 | system.connect(POWERKIT_UPOWER_SERVICE, 180 | UPOWER_PATH, 181 | POWERKIT_DBUS_PROPERTIES, 182 | DBUS_PROPERTIES_CHANGED, 183 | this, 184 | SLOT(propertiesChanged())); 185 | 186 | upower = new QDBusInterface(POWERKIT_UPOWER_SERVICE, 187 | UPOWER_PATH, 188 | UPOWER_MANAGER, 189 | system, 190 | this); 191 | logind = new QDBusInterface(POWERKIT_LOGIND_SERVICE, 192 | LOGIND_PATH, 193 | LOGIND_MANAGER, 194 | system, 195 | this); 196 | 197 | if (!upower->isValid()) { 198 | emit Error(tr("Failed to connect to upower")); 199 | return; 200 | } 201 | if (!logind->isValid()) { 202 | emit Error(tr("Failed to connect to logind")); 203 | return; 204 | } 205 | 206 | wasDocked = IsDocked(); 207 | wasLidClosed = LidIsClosed(); 208 | wasOnBattery = OnBattery(); 209 | 210 | connect(logind, 211 | SIGNAL(PrepareForSleep(bool)), 212 | this, 213 | SLOT(handlePrepareForSuspend(bool))); 214 | 215 | if (!suspendLock) { registerSuspendLock(); } 216 | if (!lidLock) { registerLidLock(); } 217 | 218 | scan(); 219 | } 220 | 221 | void Manager::check() 222 | { 223 | if (!suspendLock) { registerSuspendLock(); } 224 | if (!lidLock) { registerLidLock(); } 225 | } 226 | 227 | void Manager::scan() 228 | { 229 | QStringList foundDevices = find(); 230 | for (int i=0; i < foundDevices.size(); i++) { 231 | QString foundDevicePath = foundDevices.at(i); 232 | if (devices.contains(foundDevicePath)) { continue; } 233 | Device *newDevice = new Device(foundDevicePath, this); 234 | connect(newDevice, 235 | SIGNAL(deviceChanged(QString)), 236 | this, 237 | SLOT(handleDeviceChanged(QString))); 238 | devices[foundDevicePath] = newDevice; 239 | } 240 | UpdateDevices(); 241 | emit UpdatedDevices(); 242 | } 243 | 244 | void Manager::deviceAdded(const QDBusObjectPath &obj) 245 | { 246 | deviceAdded(obj.path()); 247 | } 248 | 249 | void Manager::deviceAdded(const QString &path) 250 | { 251 | qDebug() << "device added" << path; 252 | if (!upower->isValid()) { return; } 253 | if (path.startsWith(QString(DBUS_JOBS).arg(UPOWER_PATH))) { return; } 254 | emit DeviceWasAdded(path); 255 | scan(); 256 | } 257 | 258 | void Manager::deviceRemoved(const QDBusObjectPath &obj) 259 | { 260 | deviceRemoved(obj.path()); 261 | } 262 | 263 | void Manager::deviceRemoved(const QString &path) 264 | { 265 | qDebug() << "device removed" << path; 266 | if (!upower->isValid()) { return; } 267 | bool deviceExists = devices.contains(path); 268 | if (path.startsWith(QString(DBUS_JOBS).arg(UPOWER_PATH))) { return; } 269 | if (deviceExists) { 270 | if (find().contains(path)) { return; } 271 | delete devices.take(path); 272 | emit DeviceWasRemoved(path); 273 | } 274 | scan(); 275 | } 276 | 277 | void Manager::deviceChanged() 278 | { 279 | emit UpdatedDevices(); 280 | } 281 | 282 | void Manager::propertiesChanged() 283 | { 284 | bool closed = LidIsClosed(); 285 | bool battery = OnBattery(); 286 | bool docked = IsDocked(); 287 | 288 | qDebug() << "properties changed:" 289 | << "lid closed?" << wasLidClosed << closed 290 | << "on battery?" << wasOnBattery << battery 291 | << "is docked?" << wasDocked << docked; 292 | 293 | if (wasLidClosed != closed) { 294 | if (!wasLidClosed && closed) { 295 | qDebug() << "lid changed to closed"; 296 | emit LidClosed(); 297 | } else if (wasLidClosed && !closed) { 298 | qDebug() << "lid changed to open"; 299 | emit LidOpened(); 300 | } 301 | emit isLidClosedChanged(closed); 302 | qDebug() << "is lid closed changed" << closed; 303 | } 304 | wasLidClosed = closed; 305 | 306 | if (wasOnBattery != battery) { 307 | if (!wasOnBattery && battery) { 308 | qDebug() << "switched to battery power"; 309 | emit SwitchedToBattery(); 310 | } else if (wasOnBattery && !battery) { 311 | qDebug() << "switched to ac power"; 312 | emit SwitchedToAC(); 313 | } 314 | qDebug() << "is on battery changed" << battery; 315 | emit isOnBatteryChanged(battery); 316 | } 317 | wasOnBattery = battery; 318 | 319 | if (wasDocked != docked) { 320 | qDebug() << "is docked changed" << docked; 321 | emit isDockedChanged(docked); 322 | } 323 | wasDocked = docked; 324 | 325 | deviceChanged(); 326 | } 327 | 328 | void Manager::handleDeviceChanged(const QString &device) 329 | { 330 | Q_UNUSED(device) 331 | qDebug() << "device changed" << device; 332 | deviceChanged(); 333 | } 334 | 335 | void Manager::handlePrepareForSuspend(bool prepare) 336 | { 337 | qDebug() << "handle prepare for suspend/resume" << prepare; 338 | if (prepare) { 339 | qDebug() << "ZZZ"; 340 | LockScreen(); 341 | emit PrepareForSuspend(); 342 | QTimer::singleShot(500, this, SLOT(ReleaseSuspendLock())); 343 | } 344 | else { 345 | qDebug() << "WAKE UP!"; 346 | UpdateDevices(); 347 | emit PrepareForResume(); 348 | QTimer::singleShot(500, this, SLOT(registerSuspendLock())); 349 | } 350 | } 351 | 352 | void Manager::clearDevices() 353 | { 354 | QMapIterator device(devices); 355 | while (device.hasNext()) { 356 | device.next(); 357 | delete device.value(); 358 | } 359 | devices.clear(); 360 | } 361 | 362 | void Manager::handleNewInhibitScreenSaver(const QString &application, 363 | const QString &reason, 364 | quint32 cookie) 365 | { 366 | qDebug() << "new screensaver cookie" << application << reason << cookie; 367 | Q_UNUSED(reason) 368 | ssInhibitors[cookie] = application; 369 | emit UpdatedInhibitors(); 370 | } 371 | 372 | void Manager::handleNewInhibitPowerManagement(const QString &application, 373 | const QString &reason, 374 | quint32 cookie) 375 | { 376 | qDebug() << "new power cookie" << application << reason << cookie; 377 | Q_UNUSED(reason) 378 | pmInhibitors[cookie] = application; 379 | emit UpdatedInhibitors(); 380 | } 381 | 382 | void Manager::handleDelInhibitScreenSaver(quint32 cookie) 383 | { 384 | qDebug() << "remove screensaver cookie" << cookie; 385 | if (ssInhibitors.contains(cookie)) { 386 | ssInhibitors.remove(cookie); 387 | emit UpdatedInhibitors(); 388 | } 389 | } 390 | 391 | void Manager::handleDelInhibitPowerManagement(quint32 cookie) 392 | { 393 | qDebug() << "remove power cookie" << cookie; 394 | if (pmInhibitors.contains(cookie)) { 395 | pmInhibitors.remove(cookie); 396 | emit UpdatedInhibitors(); 397 | } 398 | } 399 | 400 | bool Manager::registerSuspendLock() 401 | { 402 | if (suspendLock) { return false; } 403 | qDebug() << "register suspend lock"; 404 | QDBusReply reply; 405 | if (logind->isValid()) { 406 | reply = logind->call("Inhibit", 407 | "sleep", 408 | "powerkit", 409 | "Lock screen etc", 410 | "delay"); 411 | } 412 | if (reply.isValid()) { 413 | suspendLock.reset(new QDBusUnixFileDescriptor(reply.value())); 414 | return true; 415 | } else { 416 | emit Warning(tr("Failed to set suspend lock: %1").arg(reply.error().message())); 417 | } 418 | return false; 419 | } 420 | 421 | bool Manager::registerLidLock() 422 | { 423 | if (lidLock) { return false; } 424 | qDebug() << "register lid lock"; 425 | QDBusReply reply; 426 | if (logind->isValid()) { 427 | reply = logind->call("Inhibit", 428 | "handle-lid-switch", 429 | "powerkit", 430 | "Custom lid handler", 431 | "block"); 432 | } 433 | if (reply.isValid()) { 434 | lidLock.reset(new QDBusUnixFileDescriptor(reply.value())); 435 | return true; 436 | } else { 437 | emit Warning(tr("Failed to set lid lock: %1").arg(reply.error().message())); 438 | } 439 | return false; 440 | } 441 | 442 | bool Manager::HasSuspendLock() 443 | { 444 | return suspendLock; 445 | } 446 | 447 | bool Manager::HasLidLock() 448 | { 449 | return lidLock; 450 | } 451 | 452 | bool Manager::CanRestart() 453 | { 454 | if (logind->isValid()) { return canLogind(PK_CAN_RESTART); } 455 | return false; 456 | } 457 | 458 | bool Manager::CanPowerOff() 459 | { 460 | if (logind->isValid()) { return canLogind(PK_CAN_POWEROFF); } 461 | return false; 462 | } 463 | 464 | bool Manager::CanSuspend() 465 | { 466 | if (logind->isValid()) { return canLogind(PK_CAN_SUSPEND); } 467 | return false; 468 | } 469 | 470 | bool Manager::CanHibernate() 471 | { 472 | if (logind->isValid()) { return canLogind(PK_CAN_HIBERNATE); } 473 | return false; 474 | } 475 | 476 | bool Manager::CanHybridSleep() 477 | { 478 | if (logind->isValid()) { return canLogind(PK_CAN_HYBRIDSLEEP); } 479 | return false; 480 | } 481 | 482 | bool Manager::CanSuspendThenHibernate() 483 | { 484 | if (logind->isValid()) { return canLogind(PK_CAN_SUSPEND_THEN_HIBERNATE); } 485 | return false; 486 | } 487 | 488 | const QString Manager::Restart() 489 | { 490 | const auto reply = callLogind(PK_RESTART); 491 | qDebug() << "restart reply" << reply; 492 | return reply.errorMessage(); 493 | } 494 | 495 | const QString Manager::PowerOff() 496 | { 497 | const auto reply = callLogind(PK_POWEROFF); 498 | qDebug() << "poweroff reply" << reply; 499 | return reply.errorMessage(); 500 | } 501 | 502 | const QString Manager::Suspend() 503 | { 504 | const auto reply = callLogind(PK_SUSPEND); 505 | qDebug() << "suspend reply" << reply; 506 | return reply.errorMessage(); 507 | } 508 | 509 | const QString Manager::Hibernate() 510 | { 511 | const auto reply = callLogind(PK_HIBERNATE); 512 | qDebug() << "hibernate reply" << reply; 513 | return reply.errorMessage(); 514 | } 515 | 516 | const QString Manager::HybridSleep() 517 | { 518 | const auto reply = callLogind(PK_HYBRIDSLEEP); 519 | qDebug() << "hybridsleep reply" << reply; 520 | return reply.errorMessage(); 521 | } 522 | 523 | const QString Manager::SuspendThenHibernate() 524 | { 525 | const auto reply = callLogind(PK_SUSPEND_THEN_HIBERNATE); 526 | qDebug() << "suspend then hibernate reply" << reply; 527 | return reply.errorMessage(); 528 | } 529 | 530 | bool Manager::IsDocked() 531 | { 532 | if (logind->isValid()) { return logind->property(LOGIND_DOCKED).toBool(); } 533 | return false; 534 | } 535 | 536 | bool Manager::LidIsPresent() 537 | { 538 | if (upower->isValid()) { return upower->property(UPOWER_LID_IS_PRESENT).toBool(); } 539 | return false; 540 | } 541 | 542 | bool Manager::LidIsClosed() 543 | { 544 | if (upower->isValid()) { return upower->property(UPOWER_LID_IS_CLOSED).toBool(); } 545 | return false; 546 | } 547 | 548 | bool Manager::OnBattery() 549 | { 550 | if (upower->isValid()) { return upower->property(UPOWER_ON_BATTERY).toBool(); } 551 | return false; 552 | } 553 | 554 | double Manager::BatteryLeft() 555 | { 556 | if (OnBattery()) { UpdateBattery(); } 557 | double batteryLeft = 0; 558 | QMapIterator device(devices); 559 | int batteries = 0; 560 | while (device.hasNext()) { 561 | device.next(); 562 | if (device.value()->isBattery && 563 | device.value()->isPresent && 564 | !device.value()->nativePath.isEmpty()) 565 | { 566 | batteryLeft += device.value()->percentage; 567 | batteries++; 568 | } else { continue; } 569 | } 570 | return batteryLeft/batteries; 571 | } 572 | 573 | void Manager::LockScreen() 574 | { 575 | qDebug() << "screen lock"; 576 | QProcess::startDetached(Settings::getValue(CONF_SCREENSAVER_LOCK_CMD, 577 | POWERKIT_SCREENSAVER_LOCK_CMD).toString(), 578 | QStringList()); 579 | QProcess::execute("xset", 580 | QStringList() << "dpms" << "force" << "off"); 581 | } 582 | 583 | bool Manager::HasBattery() 584 | { 585 | QMapIterator device(devices); 586 | while (device.hasNext()) { 587 | device.next(); 588 | if (device.value()->isBattery) { return true; } 589 | } 590 | return false; 591 | } 592 | 593 | qlonglong Manager::TimeToEmpty() 594 | { 595 | if (OnBattery()) { UpdateBattery(); } 596 | qlonglong result = 0; 597 | QMapIterator device(devices); 598 | while (device.hasNext()) { 599 | device.next(); 600 | if (device.value()->isBattery && 601 | device.value()->isPresent && 602 | !device.value()->nativePath.isEmpty()) 603 | { result += device.value()->timeToEmpty; } 604 | } 605 | return result; 606 | } 607 | 608 | qlonglong Manager::TimeToFull() 609 | { 610 | if (OnBattery()) { UpdateBattery(); } 611 | qlonglong result = 0; 612 | QMapIterator device(devices); 613 | while (device.hasNext()) { 614 | device.next(); 615 | if (device.value()->isBattery && 616 | device.value()->isPresent && 617 | !device.value()->nativePath.isEmpty()) 618 | { result += device.value()->timeToFull; } 619 | } 620 | return result; 621 | } 622 | 623 | void Manager::UpdateDevices() 624 | { 625 | QMapIterator device(devices); 626 | while (device.hasNext()) { 627 | device.next(); 628 | device.value()->update(); 629 | } 630 | } 631 | 632 | void Manager::UpdateBattery() 633 | { 634 | QMapIterator device(devices); 635 | while (device.hasNext()) { 636 | device.next(); 637 | if (device.value()->isBattery) { 638 | device.value()->updateBattery(); 639 | } 640 | } 641 | } 642 | 643 | void Manager::UpdateConfig() 644 | { 645 | emit Update(); 646 | } 647 | 648 | const QStringList Manager::GetScreenSaverInhibitors() 649 | { 650 | QStringList result; 651 | QMapIterator i(ssInhibitors); 652 | while (i.hasNext()) { 653 | i.next(); 654 | result << i.value(); 655 | } 656 | return result; 657 | } 658 | 659 | const QStringList Manager::GetPowerManagementInhibitors() 660 | { 661 | QStringList result; 662 | QMapIterator i(pmInhibitors); 663 | while (i.hasNext()) { 664 | i.next(); 665 | result << i.value(); 666 | } 667 | return result; 668 | } 669 | 670 | QMap Manager::GetInhibitors() 671 | { 672 | QMap result; 673 | QMapIterator ss(ssInhibitors); 674 | while (ss.hasNext()) { 675 | ss.next(); 676 | result.insert(ss.key(), ss.value()); 677 | } 678 | QMapIterator pm(pmInhibitors); 679 | while (pm.hasNext()) { 680 | pm.next(); 681 | result.insert(pm.key(), pm.value()); 682 | } 683 | return result; 684 | } 685 | 686 | void Manager::ReleaseSuspendLock() 687 | { 688 | qDebug() << "release suspend lock"; 689 | suspendLock.reset(nullptr); 690 | } 691 | 692 | void Manager::ReleaseLidLock() 693 | { 694 | qDebug() << "release lid lock"; 695 | lidLock.reset(nullptr); 696 | } 697 | -------------------------------------------------------------------------------- /src/powerkit_manager.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_MANAGER_H 10 | #define POWERKIT_MANAGER_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "powerkit_device.h" 23 | 24 | namespace PowerKit 25 | { 26 | class Manager : public QObject 27 | { 28 | Q_OBJECT 29 | 30 | public: 31 | explicit Manager(QObject *parent = 0); 32 | ~Manager(); 33 | QMap getDevices(); 34 | 35 | private: 36 | QMap devices; 37 | QMap ssInhibitors; 38 | QMap pmInhibitors; 39 | 40 | QDBusInterface *upower; 41 | QDBusInterface *logind; 42 | 43 | QTimer timer; 44 | 45 | bool wasDocked; 46 | bool wasLidClosed; 47 | bool wasOnBattery; 48 | 49 | QScopedPointer suspendLock; 50 | QScopedPointer lidLock; 51 | 52 | signals: 53 | void Update(); 54 | void UpdatedDevices(); 55 | void LidClosed(); 56 | void LidOpened(); 57 | void SwitchedToBattery(); 58 | void SwitchedToAC(); 59 | void PrepareForSuspend(); 60 | void PrepareForResume(); 61 | void DeviceWasRemoved(const QString &path); 62 | void DeviceWasAdded(const QString &path); 63 | void UpdatedInhibitors(); 64 | void Error(const QString &message); 65 | void Warning(const QString &message); 66 | 67 | void isDockedChanged(bool isDocked); 68 | void isLidClosedChanged(bool isClosed); 69 | void isOnBatteryChanged(bool onBattery); 70 | 71 | 72 | private slots: 73 | bool canLogind(const QString &method); 74 | const QDBusMessage callLogind(const QString &method); 75 | 76 | QStringList find(); 77 | void setup(); 78 | void check(); 79 | void scan(); 80 | 81 | void deviceAdded(const QDBusObjectPath &obj); 82 | void deviceAdded(const QString &path); 83 | void deviceRemoved(const QDBusObjectPath &obj); 84 | void deviceRemoved(const QString &path); 85 | void deviceChanged(); 86 | void propertiesChanged(); 87 | void handleDeviceChanged(const QString &device); 88 | void handlePrepareForSuspend(bool prepare); 89 | void clearDevices(); 90 | void handleNewInhibitScreenSaver(const QString &application, 91 | const QString &reason, 92 | quint32 cookie); 93 | void handleNewInhibitPowerManagement(const QString &application, 94 | const QString &reason, 95 | quint32 cookie); 96 | void handleDelInhibitScreenSaver(quint32 cookie); 97 | void handleDelInhibitPowerManagement(quint32 cookie); 98 | 99 | bool registerSuspendLock(); 100 | bool registerLidLock(); 101 | 102 | public slots: 103 | bool HasSuspendLock(); 104 | bool HasLidLock(); 105 | 106 | bool CanRestart(); 107 | bool CanPowerOff(); 108 | bool CanSuspend(); 109 | bool CanHibernate(); 110 | bool CanHybridSleep(); 111 | bool CanSuspendThenHibernate(); 112 | 113 | const QString Restart(); 114 | const QString PowerOff(); 115 | const QString Suspend(); 116 | const QString Hibernate(); 117 | const QString HybridSleep(); 118 | const QString SuspendThenHibernate(); 119 | 120 | bool IsDocked(); 121 | bool LidIsPresent(); 122 | bool LidIsClosed(); 123 | bool OnBattery(); 124 | double BatteryLeft(); 125 | void LockScreen(); 126 | bool HasBattery(); 127 | qlonglong TimeToEmpty(); 128 | qlonglong TimeToFull(); 129 | void UpdateDevices(); 130 | void UpdateBattery(); 131 | void UpdateConfig(); 132 | const QStringList GetScreenSaverInhibitors(); 133 | const QStringList GetPowerManagementInhibitors(); 134 | QMap GetInhibitors(); 135 | void ReleaseSuspendLock(); 136 | void ReleaseLidLock(); 137 | }; 138 | } 139 | 140 | #endif // POWERKIT_MANAGER_H 141 | -------------------------------------------------------------------------------- /src/powerkit_notify.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) 2018-2022 Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include "powerkit_notify.h" 10 | #include "powerkit_common.h" 11 | 12 | #define NOTIFY_SERVICE "org.freedesktop.Notifications" 13 | #define NOTIFY_PATH "/org/freedesktop/Notifications" 14 | 15 | using namespace PowerKit; 16 | 17 | SystemNotification::SystemNotification(QObject* parent) 18 | : QObject(parent) 19 | { 20 | dbus = 21 | new QDBusInterface(NOTIFY_SERVICE, 22 | NOTIFY_PATH, 23 | NOTIFY_SERVICE, 24 | QDBusConnection::sessionBus(), 25 | this); 26 | valid = dbus->isValid(); 27 | } 28 | 29 | void SystemNotification::sendMessage(const QString& title, 30 | const QString& text, 31 | const bool critical) 32 | { 33 | QList args; 34 | QVariantMap hintsMap; 35 | int timeout = 5000; 36 | 37 | if (critical) { 38 | hintsMap.insert("urgency", QVariant::fromValue(uchar(2))); 39 | timeout = 0; 40 | } 41 | 42 | args << (qAppName()) // appname 43 | << static_cast(0) // id 44 | << POWERKIT_ICON // icon 45 | << title // summary 46 | << text // body 47 | << QStringList() // actions 48 | << hintsMap // hints 49 | << timeout; // timeout 50 | dbus->callWithArgumentList( QDBus::AutoDetect, QString("Notify"), args); 51 | } 52 | -------------------------------------------------------------------------------- /src/powerkit_notify.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) 2018-2022 Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_NOTIFY_H 10 | #define POWERKIT_NOTIFY_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | class QDBusInterface; 19 | 20 | namespace PowerKit 21 | { 22 | class SystemNotification : public QObject 23 | { 24 | Q_OBJECT 25 | 26 | public: 27 | explicit SystemNotification(QObject* parent = nullptr); 28 | bool valid; 29 | 30 | void sendMessage(const QString& title, 31 | const QString& text, 32 | const bool critical); 33 | 34 | private: 35 | QDBusInterface *dbus; 36 | }; 37 | } 38 | 39 | #endif // POWERKIT_NOTIFY_H 40 | -------------------------------------------------------------------------------- /src/powerkit_powermanagement.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include "powerkit_powermanagement.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "powerkit_common.h" 18 | 19 | #define PM_TIMEOUT 60000 20 | #define PM_MAX_INHIBIT 18000 21 | 22 | using namespace PowerKit; 23 | 24 | PowerManagement::PowerManagement(QObject *parent) : QObject(parent) 25 | { 26 | timer.setInterval(PM_TIMEOUT); 27 | connect(&timer, SIGNAL(timeout()), 28 | this, SLOT(timeOut())); 29 | timer.start(); 30 | } 31 | 32 | quint32 PowerManagement::genCookie() 33 | { 34 | quint32 cookie = QRandomGenerator::global()->generate(); 35 | while (!clients.contains(cookie)) { 36 | if (!clients.contains(cookie)) { clients[cookie] = QTime::currentTime(); } 37 | else { cookie = QRandomGenerator::global()->generate(); } 38 | } 39 | return cookie; 40 | } 41 | 42 | void PowerManagement::checkForExpiredClients() 43 | { 44 | QMapIterator client(clients); 45 | while (client.hasNext()) { 46 | client.next(); 47 | if (client.value() 48 | .secsTo(QTime::currentTime())>=PM_MAX_INHIBIT) { 49 | clients.remove(client.key()); 50 | } 51 | } 52 | } 53 | 54 | bool PowerManagement::canInhibit() 55 | { 56 | checkForExpiredClients(); 57 | if (clients.size()>0) { return true; } 58 | return false; 59 | } 60 | 61 | void PowerManagement::timeOut() 62 | { 63 | if (canInhibit()) { SimulateUserActivity(); } 64 | } 65 | 66 | void PowerManagement::SimulateUserActivity() 67 | { 68 | qDebug() << "SimulateUserActivity"; 69 | emit HasInhibitChanged(true); 70 | } 71 | 72 | quint32 PowerManagement::Inhibit(const QString &application, 73 | const QString &reason) 74 | { 75 | qDebug() << "Inhibit" << application << reason; 76 | quint32 cookie = genCookie(); 77 | timeOut(); 78 | emit newInhibit(application, reason, cookie); 79 | emit HasInhibitChanged(canInhibit()); 80 | return cookie; 81 | } 82 | 83 | void PowerManagement::UnInhibit(quint32 cookie) 84 | { 85 | qDebug() << "UnInhibit" << cookie; 86 | if (clients.contains(cookie)) { clients.remove(cookie); } 87 | timeOut(); 88 | emit removedInhibit(cookie); 89 | emit HasInhibitChanged(canInhibit()); 90 | } 91 | 92 | bool PowerManagement::HasInhibit() 93 | { 94 | return canInhibit(); 95 | } 96 | -------------------------------------------------------------------------------- /src/powerkit_powermanagement.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_POWERMANAGEMENT_H 10 | #define POWERKIT_POWERMANAGEMENT_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace PowerKit 19 | { 20 | class PowerManagement : public QObject 21 | { 22 | Q_OBJECT 23 | 24 | public: 25 | explicit PowerManagement(QObject *parent = NULL); 26 | 27 | private: 28 | QTimer timer; 29 | QMap clients; 30 | 31 | signals: 32 | void HasInhibitChanged(bool has_inhibit_changed); 33 | void newInhibit(const QString &application, 34 | const QString &reason, 35 | quint32 cookie); 36 | void removedInhibit(quint32 cookie); 37 | 38 | private slots: 39 | quint32 genCookie(); 40 | void checkForExpiredClients(); 41 | bool canInhibit(); 42 | void timeOut(); 43 | 44 | public slots: 45 | void SimulateUserActivity(); 46 | quint32 Inhibit(const QString &application, 47 | const QString &reason); 48 | void UnInhibit(quint32 cookie); 49 | bool HasInhibit(); 50 | }; 51 | } 52 | 53 | #endif // POWERKIT_POWERMANAGEMENT_H 54 | -------------------------------------------------------------------------------- /src/powerkit_screensaver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include "powerkit_screensaver.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "powerkit_common.h" 19 | #include "powerkit_settings.h" 20 | 21 | #include 22 | #include 23 | 24 | // fix Xrandr 25 | #ifdef Bool 26 | #undef Bool 27 | #endif 28 | #ifdef Unsorted 29 | #undef Unsorted 30 | #endif 31 | //#undef CursorShape 32 | //#undef Status 33 | //#undef None 34 | //#undef KeyPress 35 | //#undef KeyRelease 36 | //#undef FocusIn 37 | //#undef FocusOut 38 | //#undef FontChange 39 | //#undef Expose 40 | //#undef FrameFeature 41 | 42 | #define PK_SCREENSAVER_TIMER 10000 43 | #define PK_SCREENSAVER_MAX_INHIBIT 18000 44 | #define PK_SCREENSAVER_ACTIVITY "SimulateUserActivity" 45 | 46 | using namespace PowerKit; 47 | 48 | ScreenSaver::ScreenSaver(QObject *parent) 49 | : QObject(parent) 50 | , blank(POWERKIT_SCREENSAVER_TIMEOUT_BLANK) 51 | { 52 | timer.setInterval(PK_SCREENSAVER_TIMER); 53 | connect(&timer, SIGNAL(timeout()), 54 | this, SLOT(timeOut())); 55 | timer.start(); 56 | Update(); 57 | } 58 | 59 | quint32 ScreenSaver::genCookie() 60 | { 61 | quint32 cookie = QRandomGenerator::global()->generate(); 62 | while (!clients.contains(cookie)) { 63 | if (!clients.contains(cookie)) { clients[cookie] = QTime::currentTime(); } 64 | else { cookie = QRandomGenerator::global()->generate(); } 65 | } 66 | return cookie; 67 | } 68 | 69 | void ScreenSaver::checkForExpiredClients() 70 | { 71 | QMapIterator client(clients); 72 | while (client.hasNext()) { 73 | client.next(); 74 | if (client.value() 75 | .secsTo(QTime::currentTime()) >= PK_SCREENSAVER_MAX_INHIBIT) { 76 | clients.remove(client.key()); 77 | } 78 | } 79 | } 80 | 81 | bool ScreenSaver::canInhibit() 82 | { 83 | checkForExpiredClients(); 84 | if (clients.size() > 0) { return true; } 85 | return false; 86 | } 87 | 88 | void ScreenSaver::timeOut() 89 | { 90 | if (canInhibit()) { 91 | SimulateUserActivity(); 92 | return; 93 | } 94 | int idle = GetSessionIdleTime(); 95 | qDebug() << "screensaver idle" << idle << blank; 96 | if (idle >= blank) { Lock(); } 97 | } 98 | 99 | void ScreenSaver::Update() 100 | { 101 | xlock = Settings::getValue(CONF_SCREENSAVER_LOCK_CMD, 102 | POWERKIT_SCREENSAVER_LOCK_CMD).toString(); 103 | blank = Settings::getValue(CONF_SCREENSAVER_TIMEOUT_BLANK, 104 | POWERKIT_SCREENSAVER_TIMEOUT_BLANK).toInt(); 105 | int exe1 = QProcess::execute("xset", 106 | QStringList() << "-dpms"); 107 | int exe2 = QProcess::execute("xset", 108 | QStringList() << "s" << "on"); 109 | int exe3 = QProcess::execute("xset", 110 | QStringList() << "s" << QString::number(blank)); 111 | qDebug() << "screensaver update" << exe1 << exe2 << exe3; 112 | SimulateUserActivity(); 113 | } 114 | 115 | void ScreenSaver::Lock() 116 | { 117 | if (xlock.isEmpty()) { return; } 118 | qDebug() << "screensaver lock"; 119 | QProcess::startDetached(xlock, QStringList()); 120 | setDisplaysOff(true); 121 | } 122 | 123 | void ScreenSaver::SimulateUserActivity() 124 | { 125 | int exe = QProcess::execute("xset", 126 | QStringList() << "s" << "reset"); 127 | qDebug() << "screensaver reset" << exe; 128 | } 129 | 130 | quint32 ScreenSaver::GetSessionIdleTime() 131 | { 132 | quint32 idle = 0; 133 | Display *display = XOpenDisplay(0); 134 | if (display != 0) { 135 | XScreenSaverInfo *info = XScreenSaverAllocInfo(); 136 | XScreenSaverQueryInfo(display, 137 | DefaultRootWindow(display), 138 | info); 139 | if (info) { 140 | idle = info->idle; 141 | XFree(info); 142 | } 143 | } 144 | XCloseDisplay(display); 145 | quint32 secs = idle / 1000; 146 | return secs; 147 | } 148 | 149 | quint32 ScreenSaver::Inhibit(const QString &application_name, 150 | const QString &reason_for_inhibit) 151 | { 152 | quint32 cookie = genCookie(); 153 | emit newInhibit(application_name, 154 | reason_for_inhibit, 155 | cookie); 156 | timeOut(); 157 | return cookie; 158 | } 159 | 160 | void ScreenSaver::UnInhibit(quint32 cookie) 161 | { 162 | if (clients.contains(cookie)) { clients.remove(cookie); } 163 | timeOut(); 164 | emit removedInhibit(cookie); 165 | } 166 | 167 | const QMap ScreenSaver::GetDisplays() 168 | { 169 | QMap result; 170 | Display *dpy; 171 | if ((dpy = XOpenDisplay(nullptr)) == nullptr) { return result; } 172 | XRRScreenResources *sr; 173 | XRROutputInfo *info; 174 | sr = XRRGetScreenResourcesCurrent(dpy, DefaultRootWindow(dpy)); 175 | if (sr) { 176 | for (int i = 0; i < sr->noutput;++i) { 177 | info = XRRGetOutputInfo(dpy, sr, sr->outputs[i]); 178 | if (info == nullptr) { 179 | XRRFreeOutputInfo(info); 180 | continue; 181 | } 182 | QString output = info->name; 183 | result[output] = (info->connection == RR_Connected); 184 | XRRFreeOutputInfo(info); 185 | } 186 | } 187 | XRRFreeScreenResources(sr); 188 | XCloseDisplay(dpy); 189 | return result; 190 | } 191 | 192 | const QString ScreenSaver::GetInternalDisplay() 193 | { 194 | QString result; 195 | Display *dpy; 196 | if ((dpy = XOpenDisplay(nullptr)) == nullptr) { return result; } 197 | XRRScreenResources *sr; 198 | sr = XRRGetScreenResourcesCurrent(dpy, DefaultRootWindow(dpy)); 199 | if (sr) { 200 | XRROutputInfo *info = XRRGetOutputInfo(dpy, sr, sr->outputs[0]); 201 | if (info) { result = info->name; } 202 | XRRFreeOutputInfo(info); 203 | } 204 | XRRFreeScreenResources(sr); 205 | XCloseDisplay(dpy); 206 | return result; 207 | } 208 | 209 | void ScreenSaver::setDisplaysOff(bool off) 210 | { 211 | int xset = QProcess::execute("xset", 212 | QStringList() << "dpms" << "force" << (off ? "off" : "on")); 213 | if (!off) { 214 | QProcess::execute("xset", 215 | QStringList() << "s" << "reset"); 216 | } 217 | qDebug() << "xset dpms force" << off << xset; 218 | } 219 | -------------------------------------------------------------------------------- /src/powerkit_screensaver.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_SCREENSAVER_H 10 | #define POWERKIT_SCREENSAVER_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace PowerKit 19 | { 20 | class ScreenSaver : public QObject 21 | { 22 | Q_OBJECT 23 | 24 | public: 25 | explicit ScreenSaver(QObject *parent = NULL); 26 | 27 | private: 28 | QTimer timer; 29 | QMap clients; 30 | int blank; 31 | QString xlock; 32 | 33 | signals: 34 | void newInhibit(const QString &application_name, 35 | const QString &reason_for_inhibit, 36 | quint32 cookie); 37 | void removedInhibit(quint32 cookie); 38 | 39 | private slots: 40 | quint32 genCookie(); 41 | void checkForExpiredClients(); 42 | bool canInhibit(); 43 | void timeOut(); 44 | 45 | public slots: 46 | void Update(); 47 | void Lock(); 48 | void SimulateUserActivity(); 49 | quint32 GetSessionIdleTime(); 50 | quint32 Inhibit(const QString &application_name, 51 | const QString &reason_for_inhibit); 52 | void UnInhibit(quint32 cookie); 53 | static const QMap GetDisplays(); 54 | static const QString GetInternalDisplay(); 55 | static void setDisplaysOff(bool off); 56 | }; 57 | } 58 | 59 | #endif // POWERKIT_SCREENSAVER_H 60 | -------------------------------------------------------------------------------- /src/powerkit_settings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include "powerkit_settings.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "powerkit_common.h" 17 | 18 | #define PK "powerkit" 19 | 20 | using namespace PowerKit; 21 | 22 | void Settings::setValue(const QString &type, 23 | const QVariant &value) 24 | { 25 | QSettings settings(PK, PK); 26 | settings.setValue(type, value); 27 | settings.sync(); 28 | } 29 | 30 | const QVariant Settings::getValue(const QString &type, 31 | const QVariant &fallback) 32 | { 33 | QSettings settings(PK, PK); 34 | return settings.value(type, fallback); 35 | } 36 | 37 | bool Settings::isValid(const QString &type) 38 | { 39 | QSettings settings(PK, PK); 40 | return settings.value(type).isValid(); 41 | } 42 | 43 | void Settings::saveDefault() 44 | { 45 | setValue(CONF_LID_BATTERY_ACTION, 46 | POWERKIT_LID_BATTERY_ACTION); 47 | setValue(CONF_LID_AC_ACTION, 48 | POWERKIT_LID_AC_ACTION); 49 | setValue(CONF_CRITICAL_BATTERY_ACTION, 50 | POWERKIT_CRITICAL_ACTION); 51 | setValue(CONF_CRITICAL_BATTERY_TIMEOUT, 52 | POWERKIT_CRITICAL_BATTERY); 53 | setValue(CONF_SUSPEND_BATTERY_TIMEOUT, 54 | POWERKIT_AUTO_SLEEP_BATTERY); 55 | setValue(CONF_TRAY_NOTIFY, 56 | true); 57 | setValue(CONF_TRAY_SHOW, 58 | true); 59 | setValue(CONF_LID_DISABLE_IF_EXTERNAL, 60 | false); 61 | setValue(CONF_SUSPEND_BATTERY_ACTION, 62 | suspendSleep); 63 | setValue(CONF_SUSPEND_AC_ACTION, 64 | suspendNone); 65 | setValue(CONF_BACKLIGHT_BATTERY_ENABLE, 66 | false); 67 | setValue(CONF_BACKLIGHT_AC_ENABLE, 68 | false); 69 | setValue(CONF_BACKLIGHT_BATTERY_DISABLE_IF_LOWER, 70 | false); 71 | setValue(CONF_BACKLIGHT_AC_DISABLE_IF_HIGHER, 72 | false); 73 | setValue(CONF_WARN_ON_LOW_BATTERY, 74 | true); 75 | setValue(CONF_WARN_ON_VERYLOW_BATTERY, 76 | true); 77 | setValue(CONF_NOTIFY_ON_BATTERY, 78 | true); 79 | setValue(CONF_NOTIFY_ON_AC, 80 | true); 81 | setValue(CONF_BACKLIGHT_MOUSE_WHEEL, 82 | true); 83 | setValue(CONF_SUSPEND_LOCK_SCREEN, 84 | true); 85 | setValue(CONF_RESUME_LOCK_SCREEN, 86 | false); 87 | } 88 | 89 | const QString Settings::getConf() 90 | { 91 | QString config = QString("%1/.config/powerkit/powerkit.conf") 92 | .arg(QDir::homePath()); 93 | if (!QFile::exists(config)) { saveDefault(); } 94 | return config; 95 | } 96 | 97 | const QString Settings::getDir() 98 | { 99 | QString config = QString("%1/.config/powerkit").arg(QDir::homePath()); 100 | if (!QFile::exists(config)) { 101 | QDir dir(config); 102 | dir.mkpath(config); 103 | } 104 | return config; 105 | } 106 | -------------------------------------------------------------------------------- /src/powerkit_settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_SETTINGS_H 10 | #define POWERKIT_SETTINGS_H 11 | 12 | #include 13 | #include 14 | 15 | #define CONF_DIALOG_GEOMETRY "dialog_geometry" 16 | #define CONF_SUSPEND_BATTERY_TIMEOUT "suspend_battery_timeout" 17 | #define CONF_SUSPEND_BATTERY_ACTION "suspend_battery_action" 18 | #define CONF_SUSPEND_AC_TIMEOUT "suspend_ac_timeout" 19 | #define CONF_SUSPEND_AC_ACTION "suspend_ac_action" 20 | #define CONF_SUSPEND_WAKEUP_HIBERNATE_BATTERY "suspend_wakeup_hibernate_battery" 21 | #define CONF_SUSPEND_WAKEUP_HIBERNATE_AC "suspend_wakeup_hibernate_ac" 22 | #define CONF_CRITICAL_BATTERY_TIMEOUT "critical_battery_timeout" 23 | #define CONF_CRITICAL_BATTERY_ACTION "critical_battery_action" 24 | #define CONF_LID_BATTERY_ACTION "lid_battery_action" 25 | #define CONF_LID_AC_ACTION "lid_ac_action" 26 | #define CONF_LID_DISABLE_IF_EXTERNAL "disable_lid_action_external_monitor" 27 | #define CONF_TRAY_NOTIFY "tray_notify" 28 | #define CONF_TRAY_SHOW "show_tray" 29 | #define CONF_LID_XRANDR "lid_xrandr_action" 30 | #define CONF_BACKLIGHT_BATTERY "backlight_battery_value" 31 | #define CONF_BACKLIGHT_BATTERY_ENABLE "backlight_battery_enable" 32 | #define CONF_BACKLIGHT_BATTERY_DISABLE_IF_LOWER "backlight_battery_disable_if_lower" 33 | #define CONF_BACKLIGHT_AC "backlight_ac_value" 34 | #define CONF_BACKLIGHT_AC_ENABLE "backlight_ac_enable" 35 | #define CONF_BACKLIGHT_AC_DISABLE_IF_HIGHER "backlight_ac_disable_if_higher" 36 | #define CONF_BACKLIGHT_MOUSE_WHEEL "backlight_mouse_wheel" 37 | #define CONF_DIALOG "dialog_geometry" 38 | #define CONF_WARN_ON_LOW_BATTERY "warn_on_low_battery" 39 | #define CONF_WARN_ON_VERYLOW_BATTERY "warn_on_verylow_battery" 40 | #define CONF_NOTIFY_ON_BATTERY "notify_on_battery" 41 | #define CONF_NOTIFY_ON_AC "notify_on_ac" 42 | #define CONF_NOTIFY_NEW_INHIBITOR "notify_new_inhibitor" 43 | #define CONF_SUSPEND_LOCK_SCREEN "lock_screen_on_suspend" 44 | #define CONF_RESUME_LOCK_SCREEN "lock_screen_on_resume" 45 | #define CONF_ICON_THEME "icon_theme" 46 | #define CONF_NATIVE_THEME "native_theme" 47 | #define CONF_KERNEL_BYPASS "kernel_cmd_bypass" 48 | #define CONF_SCREENSAVER_LOCK_CMD "screensaver_lock_cmd" 49 | #define CONF_SCREENSAVER_TIMEOUT_BLANK "screensaver_blank_timeout" 50 | 51 | namespace PowerKit 52 | { 53 | class Settings 54 | { 55 | public: 56 | static void setValue(const QString &type, 57 | const QVariant &value); 58 | static const QVariant getValue(const QString &type, 59 | const QVariant &fallback = QVariant()); 60 | static bool isValid(const QString &type); 61 | static void saveDefault(); 62 | static const QString getConf(); 63 | static const QString getDir(); 64 | }; 65 | } 66 | 67 | #endif // POWERKIT_SETTINGS_H 68 | -------------------------------------------------------------------------------- /src/powerkit_theme.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #include "powerkit_theme.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "powerkit_settings.h" 21 | 22 | #define DEFAULT_THEME "Adwaita" 23 | 24 | using namespace PowerKit; 25 | 26 | void Theme::setAppTheme(bool darker) 27 | { 28 | bool native = Settings::getValue(CONF_NATIVE_THEME, false).toBool(); 29 | if (native) { return; } 30 | qApp->setStyle("Fusion"); 31 | QPalette palette; 32 | palette.setColor(QPalette::Window, QColor(40, 40, 47)); 33 | palette.setColor(QPalette::WindowText, Qt::white); 34 | palette.setColor(QPalette::Base, QColor(33, 33, 38)); 35 | palette.setColor(QPalette::AlternateBase, QColor(40, 40, 47)); 36 | palette.setColor(QPalette::Link, Qt::white); 37 | palette.setColor(QPalette::LinkVisited, Qt::white); 38 | palette.setColor(QPalette::ToolTipText, Qt::white); 39 | palette.setColor(QPalette::ToolTipBase, Qt::black); 40 | palette.setColor(QPalette::Text, Qt::white); 41 | palette.setColor(QPalette::Button, QColor(33, 33, 38)); 42 | palette.setColor(QPalette::ButtonText, Qt::white); 43 | palette.setColor(QPalette::BrightText, Qt::red); 44 | palette.setColor(QPalette::Highlight, QColor(177, 16, 20)); 45 | palette.setColor(QPalette::HighlightedText, Qt::white); 46 | palette.setColor(QPalette::Disabled, QPalette::Text, Qt::darkGray); 47 | palette.setColor(QPalette::Disabled, QPalette::ButtonText, Qt::darkGray); 48 | if (darker) { 49 | palette.setColor(QPalette::Window, QColor(33, 33, 38)); 50 | palette.setColor(QPalette::Base, QColor(33, 33, 38)); 51 | palette.setColor(QPalette::Button, QColor(33, 33, 38)); 52 | } 53 | qApp->setPalette(palette); 54 | } 55 | 56 | void Theme::setIconTheme() 57 | { 58 | // setup icon theme search path 59 | QStringList iconsPath = QIcon::themeSearchPaths(); 60 | QString iconsHomeLocal = QString("%1/.local/share/icons").arg(QDir::homePath()); 61 | QString iconsHome = QString("%1/.icons").arg(QDir::homePath()); 62 | if (QFile::exists(iconsHomeLocal) && 63 | !iconsPath.contains(iconsHomeLocal)) { iconsPath.prepend(iconsHomeLocal); } 64 | if (QFile::exists(iconsHome) && 65 | !iconsPath.contains(iconsHome)) { iconsPath.prepend(iconsHome); } 66 | iconsPath << QString("%1/../share/icons").arg(qApp->applicationDirPath()); 67 | QIcon::setThemeSearchPaths(iconsPath); 68 | qDebug() << "using icon theme search path" << QIcon::themeSearchPaths(); 69 | 70 | QString theme = QIcon::themeName(); 71 | if (theme.isEmpty() || theme == "hicolor") { // try to load saved theme 72 | theme = Settings::getValue(CONF_ICON_THEME).toString(); 73 | } 74 | if(theme.isEmpty() || theme == "hicolor") { // Nope, then scan for first available 75 | // gtk 76 | if(QFile::exists(QDir::homePath() + "/" + ".gtkrc-2.0")) { 77 | QSettings gtkFile(QDir::homePath() + "/.gtkrc-2.0", QSettings::IniFormat); 78 | theme = gtkFile.value("gtk-icon-theme-name").toString().remove("\""); 79 | } else { 80 | QSettings gtkFile(QDir::homePath() + "/.config/gtk-3.0/settings.ini", QSettings::IniFormat); 81 | theme = gtkFile.value("gtk-fallback-icon-theme").toString().remove("\""); 82 | } 83 | // fallback 84 | if(theme.isNull()) { theme = DEFAULT_THEME; } 85 | if (!theme.isEmpty()) { Settings::setValue(CONF_ICON_THEME, theme); } 86 | } 87 | qDebug() << "Using icon theme" << theme; 88 | QIcon::setThemeName(theme); 89 | } 90 | 91 | const QPixmap Theme::drawCircleProgress(const int &progress, 92 | const int &dimension, 93 | const int &width, 94 | const int &padding, 95 | const bool dash, 96 | const QString &text, 97 | const QColor &color1, 98 | const QColor &color2, 99 | const QColor &color3) 100 | { 101 | double value = (double)progress / 100; 102 | if (value < 0.) { value = 0.; } 103 | else if (value > 1.) { value = 1.; } 104 | 105 | QRectF circle(padding / 2, 106 | padding / 2, 107 | dimension - padding, 108 | dimension - padding); 109 | 110 | int startAngle = -90 * 16; 111 | int spanAngle = value * 360 * 16; 112 | 113 | QPixmap pix(dimension, dimension); 114 | pix.fill(Qt::transparent); 115 | 116 | QPainter p(&pix); 117 | p.setRenderHint(QPainter::Antialiasing); 118 | 119 | QPen pen; 120 | pen.setWidth(width); 121 | pen.setCapStyle(Qt::FlatCap); 122 | pen.setColor(color1); 123 | if (dash) { pen.setStyle(Qt::DashLine); } 124 | 125 | QPen pen2; 126 | pen2.setWidth(width); 127 | pen2.setColor(color2); 128 | pen2.setCapStyle(Qt::FlatCap); 129 | 130 | QPen pen3; 131 | pen3.setColor(color3); 132 | 133 | p.setPen(pen); 134 | p.drawArc(circle, startAngle, 360 * 16); 135 | 136 | p.setPen(pen2); 137 | p.drawArc(circle, startAngle, spanAngle); 138 | 139 | if (!text.isEmpty()) { 140 | p.setPen(pen3); 141 | int textPadding = padding * 4; 142 | p.drawText(QRectF(textPadding / 2, 143 | textPadding / 2, 144 | dimension - textPadding, 145 | dimension - textPadding), 146 | Qt::AlignCenter, 147 | text); 148 | } 149 | 150 | return pix; 151 | } 152 | -------------------------------------------------------------------------------- /src/powerkit_theme.h: -------------------------------------------------------------------------------- 1 | /* 2 | # PowerKit 3 | # Copyright (c) Ole-André Rodlie All rights reserved. 4 | # 5 | # Available under the 3-clause BSD license 6 | # See the LICENSE file for full details 7 | */ 8 | 9 | #ifndef POWERKIT_THEME_H 10 | #define POWERKIT_THEME_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace PowerKit 17 | { 18 | class Theme 19 | { 20 | public: 21 | static void setAppTheme(bool darker = false); 22 | static void setIconTheme(); 23 | static const QPixmap drawCircleProgress(const int &progress, 24 | const int &dimension, 25 | const int &width, 26 | const int &padding, 27 | const bool dash, 28 | const QString &text, 29 | const QColor &color1 = Qt::red, 30 | const QColor &color2 = Qt::white, 31 | const QColor &color3 = Qt::white); 32 | }; 33 | } 34 | 35 | #endif // POWERKIT_THEME_H 36 | --------------------------------------------------------------------------------