ukui-power-manager/0000775000175000017500000000000015167661430013230 5ustar fengfengukui-power-manager/power/0000775000175000017500000000000015167661430014364 5ustar fengfengukui-power-manager/power/translations/0000775000175000017500000000000015167661430017105 5ustar fengfengukui-power-manager/power/translations/ky.ts0000664000175000017500000010040615167661430020101 0ustar fengfeng Power select power plan 电源计划 Balance (suggest) Баланс (сунуш) Saving Үнөмдөө Minimize performance 尽可能降低计算机能耗 Bala&nce (suggest) Autobalance energy and performance with available hardware жеткиликтүү аппараттык менен автобаланстык энергия жана аткаруу Custom 自定义 Users develop personalized power plans Колдонуучулар жекелештирилген электр пландарын иштеп чыгуу Power supply 电源供给 Battery powered 电池供给 Change PC sleep time: 系统进入空闲状态并于此时间后睡眠: Change DP close time: 系统进入空闲状态并于此时间后关闭显示器: Change pc sleep time: 系统进入空闲状态并于此时间后挂起: Change dp close time: 系统进入空闲状态并于此时间后关闭显示器: When close lid: 关闭笔记本电脑上盖时: Screen darkens use battery: 无操作状态下于此时间后减小屏幕亮度: Power Other Settings 电源图标设置 S3 to S4 when: 挂起此时间后转为睡眠: Power Icon Settings 电源图标设置 Power icon: 电源图标: power 电源 Power Күч Change PC sleep time after %1 min: 系统%1分钟后进入空闲状态并于此时间后挂起: Change DP close time after %1 min: 系统%1分钟后进入空闲状态并于此时间后关闭显示器: Enter idle state %1 min and sleep after %2 min : 系统%1分钟后进入空闲状态并于%2分钟后挂起: Enter idle state %1 min and close after %2 min : 系统%1分钟后进入空闲状态并于%2分钟后关闭显示器: never эч качан 10 min 10分钟 30 min 30分钟 60 min 60分钟 120 min 120分钟 300 min 300分钟 20 min 20分钟 1 min 1分钟 5 min 5分钟 Require password when suspend/hibernation уйку / уктап жатканда сырсөз талап Require password when suspend Require password when suspend/hibernate /Power/Require password when suspend/hibernate The system will sleep before turning off the display Reduce the occupation of backend running program resources and ensure smooth operation of key and focus applications. Battery Maximum Capacity Батареянын максималдуу кубаттуулугу This is the battery capacity relative to a new battery. A lower capacity may result in a shorter battery life after charging. Бул батареянын кубаттуулугу жаңы батареяга салыштырмалуу. Төмөн кубаттуулугу заряддалгандан кийин батареянын кыска өмүрүнө алып келиши мүмкүн. The battery capacity is low, please replace the battery. Батареянын кубаттуулугу төмөн, батареяны алмаштырыңыздар. Unable to obtain battery capacity, please contact the hardware manufacturer for repair. Батареянын кубаттуулугун ала албай, оңдоп-түзөө үчүн аппараттык өндүрүүчүгө кайрылыңыздар. Require password when hibernate Password required when waking up the screen Экранды ойгонгондо сырсөз талап кылынат /Power/Password required when waking up the screen Press the power button Кубат баскычты басуу /Power/Press the power button Time to close display Дисплейди жабуу убактысы /Power/Time to close display Time to sleep Уктай турган убак /Power/Time to sleep After this period, the system will transition from sleep to hibernation. Бул убакыттан кийин система уйку абалынан уйкуга өтөт. /Power/Time to hibernate Power plan Электр планы /Power/Using battery Notebook cover Дәптер мукабасы /Power/Notebook cover Host light strip /Power/Host light strip Dynamic resource scheduling /Power/Dynamic resource scheduling Display remaining charging and discharging time Калган кубаттоо жана разряддоо убактысын көрсөтүү Using power Күч колдонуу /Power/Using power Using battery Батареяны колдонуу /Power/Using battery Time to darken Караңгылоо убактысы Battery level is lower than Батареянын деңгээли төмөндөйт Run Чуркоо Low battery notification Батареянын аз эскертүүсү /Power/Low battery notification Automatically run saving mode when low battery Батареясы төмөн болгондо, үнөмдөө режимин автоматтык түрдө иштетүү /Power/"Automatically run saving mode when low battery Automatically run saving mode when the low battery Батареясы төмөн болгондо, үнөмдөө режимин автоматтык түрдө иштетүү Automatically run saving mode when using battery Батареяны колдонууда үнөмдөө режимин автоматтык түрдө иштетүү Display remaining charging time and usage time Заряддоо убактысын жана пайдалануу убактысын чагылдыруу Nothing Blank Shutdown 关机 Suspend Hibernate Interactive General Жалпы /Power/General using AC power using battery Select Powerplan Powerplan тандоо /Power/Select Powerplan Battery saving plan Батареяны сактоо планы /Power/Battery saving plan nothing эч нерсе blank бош suspend токтотуу hibernate уктоо interactive интерактивдүү 5min 5мин 4h 5h Balance 声道平衡 Energy Efficiency Performance Аткаруу Performance Model Аткаруу модели 20min 20мин 10minn 10分钟 15min 15мин 30min 30мин 1h 2h 10min 10мин Never Эч качан 100min 3分钟 {100m?} 3h 3h Balance Model Баланс модели Save Model Моделди сактоо 1min 1мин 3min 3分钟 shutdown өчүрүү always 显示电源图标在托盘栏 present 仅当存在电池时显示 charge 仅当使用电池时显示 Perform operations when battery is low: 低电量执行操作: General Settings 通用设置 When the power button is pressed: 按电源键时执行: ukui-power-manager/power/translations/zh_CN.ts0000664000175000017500000007570515167661430020474 0ustar fengfeng Power select power plan 电源计划 Balance (suggest) 平衡(推荐) Saving 节能 Minimize performance 尽可能降低计算机能耗 Bala&nce (suggest) Autobalance energy and performance with available hardware 利用可用的硬件自动平衡消耗与性能 Custom 自定义 Users develop personalized power plans 用户制定个性化电源计划 Power supply 电源供给 Battery powered 电池供给 Change PC sleep time: 系统进入空闲状态并于此时间后睡眠: Change DP close time: 系统进入空闲状态并于此时间后关闭显示器: Change pc sleep time: 系统进入空闲状态并于此时间后挂起: Change dp close time: 系统进入空闲状态并于此时间后关闭显示器: When close lid: 关闭笔记本电脑上盖时: Screen darkens use battery: 无操作状态下于此时间后减小屏幕亮度: Power Other Settings 电源图标设置 S3 to S4 when: 挂起此时间后转为睡眠: Power Icon Settings 电源图标设置 Power icon: 电源图标: power 电源 Power 电源 Change PC sleep time after %1 min: 系统%1分钟后进入空闲状态并于此时间后挂起: Change DP close time after %1 min: 系统%1分钟后进入空闲状态并于此时间后关闭显示器: Enter idle state %1 min and sleep after %2 min : 系统%1分钟后进入空闲状态并于%2分钟后挂起: Enter idle state %1 min and close after %2 min : 系统%1分钟后进入空闲状态并于%2分钟后关闭显示器: never 从不 10 min 10分钟 30 min 30分钟 60 min 60分钟 120 min 120分钟 300 min 300分钟 20 min 20分钟 1 min 1分钟 5 min 5分钟 Require password when suspend/hibernation 睡眠/休眠唤醒时需要密码 The system will sleep before turning off the display 系统将在关闭显示器之前进入睡眠 This is the battery capacity relative to a new battery. A lower capacity may result in a shorter battery life after charging. 这是相对于新电池的电池容量。较低的容量可能会导致充电后电池寿命缩短。 The battery capacity is low, please replace the battery. 电池电量低,请更换电池。 Unable to obtain battery capacity, please contact the hardware manufacturer for repair. 无法获取电池容量,请联系硬件制造商进行维修。 Require password when suspend 睡眠后唤醒需要密码 Require password when suspend/hibernate 睡眠/休眠后唤醒需要密码 /Power/Require password when suspend/hibernate Reduce the occupation of backend running program resources and ensure smooth operation of key and focus applications. 减少后台运行程序资源占用,保障关键应用与焦点应用流畅运行。 Battery Maximum Capacity 电池最大容量 Require password when hibernate 休眠后唤醒需要密码 Password required when waking up the screen 唤醒屏幕时需要密码 /Power/Password required when waking up the screen Press the power button 按电源键时执行 /Power/Press the power button Time to close display 此时间段后关闭显示器 /Power/Time to close display Time to sleep 此时间段后系统进入睡眠 /Power/Time to sleep After this period, the system will transition from sleep to hibernation. 此时间段后系统由睡眠进入休眠 /Power/Time to hibernate Power plan 电源计划 /Power/Using battery Notebook cover 笔记本合盖时执行 /Power/Notebook cover Host light strip 主机灯带 /Power/Host light strip Dynamic resource scheduling 资源动态调度 /Power/Dynamic resource scheduling Display remaining charging and discharging time 显示剩余充电和放电时间 Using power 使用电源时 /Power/Using power Using battery 使用电池时 /Power/Using battery Time to darken 此时间段后降低屏幕亮度 Battery level is lower than 电量低于 Run 时执行 Low battery notification 低电量时通知 /Power/Low battery notification Automatically run saving mode when low battery 低电量时自动开启节能模式 /Power/"Automatically run saving mode when low battery Automatically run saving mode when the low battery 低电量时自动开启节能模式 Automatically run saving mode when using battery 使用电池时自动开启节能模式 Display remaining charging time and usage time 显示剩余充电时间和剩余使用时间 Nothing 无操作 Blank 关闭显示器 Shutdown 关机 Suspend 睡眠 Hibernate 休眠 Interactive 询问 General 通用 /Power/General using AC power 使用电源时 using battery 使用电池时 Select Powerplan 电源计划 /Power/Select Powerplan Battery saving plan 电池节能计划 /Power/Battery saving plan nothing 无操作 blank 关闭显示器 suspend 睡眠 hibernate 休眠 interactive 询问 5min 5 分钟 4h 4 小时 5h 5 小时 Balance 平衡 Energy Efficiency 最佳能效 Performance 最佳性能 Performance Model 性能模式 20min 20分钟 10minn 10分钟 15min 15 分钟 30min 30 分钟 1h 1 小时 2h 2 小时 10min 10 分钟 Never 从不 100min 100分钟 3h 3 小时 Balance Model 平衡模式 Save Model 节能模式 1min 1 分钟 3min 3分钟 shutdown 关机 always 显示电源图标在托盘栏 present 仅当存在电池时显示 charge 仅当使用电池时显示 Perform operations when battery is low: 低电量执行操作: General Settings 通用设置 When the power button is pressed: 按电源键时执行: ukui-power-manager/power/translations/kk.ts0000664000175000017500000010114115167661430020060 0ustar fengfeng Power select power plan 电源计划 Balance (suggest) Баланс (ұсыныс) Saving Сақтау Minimize performance 尽可能降低计算机能耗 Bala&nce (suggest) Autobalance energy and performance with available hardware Қолда бар аппараттық құралдары бар энергияны және өнімділікті автобананстау Custom 自定义 Users develop personalized power plans Пайдаланушылар дербестендірілген қуат жоспарларын әзірлейді Power supply 电源供给 Battery powered 电池供给 Change PC sleep time: 系统进入空闲状态并于此时间后睡眠: Change DP close time: 系统进入空闲状态并于此时间后关闭显示器: Change pc sleep time: 系统进入空闲状态并于此时间后挂起: Change dp close time: 系统进入空闲状态并于此时间后关闭显示器: When close lid: 关闭笔记本电脑上盖时: Screen darkens use battery: 无操作状态下于此时间后减小屏幕亮度: Power Other Settings 电源图标设置 S3 to S4 when: 挂起此时间后转为睡眠: Power Icon Settings 电源图标设置 Power icon: 电源图标: power 电源 Power Қуат Change PC sleep time after %1 min: 系统%1分钟后进入空闲状态并于此时间后挂起: Change DP close time after %1 min: 系统%1分钟后进入空闲状态并于此时间后关闭显示器: Enter idle state %1 min and sleep after %2 min : 系统%1分钟后进入空闲状态并于%2分钟后挂起: Enter idle state %1 min and close after %2 min : 系统%1分钟后进入空闲状态并于%2分钟后关闭显示器: never ешқашан 10 min 10分钟 30 min 30分钟 60 min 60分钟 120 min 120分钟 300 min 300分钟 20 min 20分钟 1 min 1分钟 5 min 5分钟 Require password when suspend/hibernation Ұйқы/хибернация кезінде парольді талап ету Require password when suspend Require password when suspend/hibernate /Power/Require password when suspend/hibernate The system will sleep before turning off the display Reduce the occupation of backend running program resources and ensure smooth operation of key and focus applications. Battery Maximum Capacity Батареяның ең жоғары сыйымдылығы This is the battery capacity relative to a new battery. A lower capacity may result in a shorter battery life after charging. Бұл жаңа аккумуляторлық батареяға қатысты аккумуляторлық батареяның сыйымдылығы. Сыйымдылықтың төмендеуі зарядтаудан кейін аккумуляторлық батареялардың қызмет ету мерзімінің қысқаруына әкелуі мүмкін. The battery capacity is low, please replace the battery. Аккумулятор батареясының сыйымдылығы төмен, аккумулятор батареясын ауыстыруыңызды сұраймыз. Unable to obtain battery capacity, please contact the hardware manufacturer for repair. Аккумуляторлық батареялардың қуатын ала алмай, жөндеу үшін аппарат өндірушіге хабарласуыңызды сұраймыз. Require password when hibernate Password required when waking up the screen Экраннан оянғанда қажетті құпия сөз /Power/Password required when waking up the screen Press the power button Қуат түймешігі /Power/Press the power button Time to close display Дисплейді жабу уақыты /Power/Time to close display Time to sleep Ұйықтау уақыты /Power/Time to sleep After this period, the system will transition from sleep to hibernation. Осы уақыттан кейін жүйе ұйқы күйінен ұйқыға ауысады. /Power/Time to hibernate Power plan /Power/Using battery Notebook cover Жазу кітапшасының мұқабасы /Power/Notebook cover Host light strip /Power/Host light strip Dynamic resource scheduling /Power/Dynamic resource scheduling Display remaining charging and discharging time Қалған зарядтау және разрядтау уақытын көрсету Using power Қуатты пайдалану /Power/Using power Using battery Батареяны пайдалану /Power/Using battery Time to darken Қараңғылауға арналған уақыт Battery level is lower than Аккумуляторлық батареялардың деңгейі төмен Run Іске қосу Low battery notification Батареяның төмен хабарландыруы /Power/Low battery notification Automatically run saving mode when low battery Батарея төмен болғанда сақтау режимін автоматты түрде іске қосу /Power/"Automatically run saving mode when low battery Automatically run saving mode when the low battery Батареяның төмендігі кезінде сақтау режимін автоматты түрде іске қосу Automatically run saving mode when using battery Батареяны пайдалану кезінде сақтау режимін автоматты түрде іске қосу Display remaining charging time and usage time Зарядтаудың қалған уақытын және пайдалану уақытын көрсету Nothing Blank Shutdown 关机 Suspend Hibernate Interactive General Жалпы /Power/General using AC power using battery Select Powerplan Powerplan бағдарламасын таңдау /Power/Select Powerplan Battery saving plan Батареяны сақтау жоспары /Power/Battery saving plan nothing ештеңе жоқ blank бос suspend тоқтата тұру hibernate Хибернате interactive интерактивті 5min 5 мин 4h 4h 5h 5h Balance 声道平衡 Energy Efficiency Performance Өнімділік Performance Model Өнімділік үлгісі 20min 20 мин 10minn 10分钟 15min 15 мин 30min 30 мин 1h 1h 2h 2h 10min 10 мин Never Ешқашан 100min 3分钟 {100m?} 3h 3h Balance Model Баланс үлгісі Save Model Үлгіні сақтау 1min 1 мин 3min 3分钟 shutdown өшіру always 显示电源图标在托盘栏 present 仅当存在电池时显示 charge 仅当使用电池时显示 Perform operations when battery is low: 低电量执行操作: General Settings 通用设置 When the power button is pressed: 按电源键时执行: ukui-power-manager/power/translations/tr.ts0000664000175000017500000004600315167661430020105 0ustar fengfeng Power select power plan Güç Yönetimini Ayarla Balance (suggest) Dengeli (Önerilen) Saving Kaydediliyor Minimize performance Performansı en aza indir Bala&nce (suggest) Denge (önerilen) Autobalance energy and performance with available hardware Mevcut donanım ile enerji ve performansı otomatik olarak dengeleme Custom Özel /power/Custom Users develop personalized power plans Kullanıcılar kişiselleştirilmiş güç planları geliştirir Power supply A/C Gücünde Battery powered Pil Gücünde Change PC sleep time: PC uyku süresini değiştirin: Change DP close time: DP kapanış zamanını değiştirin: Change pc sleep time: Uyku Moduna Al: Change dp close time: Bilgisayarı Kapat: When close lid: Kapak Kapandığında: Screen darkens use battery: Pilde Ekranı Kapatma Süresi: Power Other Settings Diğer Güç Ayarları S3 to S4 when: S3 ile S4 durumlarında: Power Icon Settings Güç Simgesi Ayarları Power icon: Güç Simgesi: power Güç Power Güç The system will sleep before turning off the display Reduce the occupation of backend running program resources and ensure smooth operation of key and focus applications. Battery Maximum Capacity Pil Maksimum Kapasitesi Require password when suspend Require password when suspend/hibernate /Power/Require password when suspend/hibernate This is the battery capacity relative to a new battery. A lower capacity may result in a shorter battery life after charging. Bu yeni bir bateriyle ilişkin bateri kapasitesi. Daha düşük kapasitet yüklenmeden sonra daha kısa bir bateri hayatına neden olabilir. The battery capacity is low, please replace the battery. Batarya kapasitesi düşük, lütfen batteriyi değiştirin. Unable to obtain battery capacity, please contact the hardware manufacturer for repair. Batarya kapasitesi alınamadı, lütfen tamir için donanım üreticisine bağlantı edin. Require password when hibernate never Asla 10 min 10 dk 30 min 30 dk 60 min 60 dk 120 min 120 dk 300 min 300 dk 20 min 20 dk 1 min 1 dk 5 min 5 dk Password required when waking up the screen /Power/Password required when waking up the screen Press the power button /Power/Press the power button Time to close display /Power/Time to close display Time to sleep /Power/Time to sleep Notebook cover /Power/Notebook cover Host light strip /Power/Host light strip Dynamic resource scheduling /Power/Dynamic resource scheduling Using power /Power/Using power Using battery /Power/Using battery Time to darken Battery level is lower than Run Low battery notification /Power/Low battery notification Automatically run saving mode when low battery /Power/"Automatically run saving mode when low battery Automatically run saving mode when the low battery Automatically run saving mode when using battery Display remaining charging time and usage time Nothing Blank Shutdown Kapat Suspend Hibernate Interactive General /Power/General Select Powerplan /Power/Select Powerplan Battery saving plan /Power/Battery saving plan nothing Hiçbiri blank Boş suspend Askıya Al hibernate Beklemeye Al 5min 10min 15min 30min 1h 1 sa 2h 3 sa {2h?} Never Asla 3h 3 sa Balance Denge Energy Efficiency Performance Performans shutdown Kapat always Her Zaman present Mevcut charge Şarj ukui-power-manager/power/translations/ug.ts0000664000175000017500000010037215167661430020073 0ustar fengfeng Power select power plan 电源计划 Balance (suggest) تەڭپۇڭلۇق (تەۋسىيە) Saving ساقلاۋاتىدۇ Minimize performance 尽可能降低计算机能耗 Bala&nce (suggest) Autobalance energy and performance with available hardware ئىشلىتىشكە بولىدىغان قاتتىق دېتال ئارقىلىق ئاپتوماتىك تەڭپۇڭلۇق ئېنېرگىيەسى ۋە ئىقتىدارى Custom 自定义 Users develop personalized power plans ئابونتلار شەخسىي ھوقۇق پىلانى تۈزۈپ چىقىش Power supply 电源供给 Battery powered 电池供给 Change PC sleep time: 系统进入空闲状态并于此时间后睡眠: Change DP close time: 系统进入空闲状态并于此时间后关闭显示器: Change pc sleep time: 系统进入空闲状态并于此时间后挂起: Change dp close time: 系统进入空闲状态并于此时间后关闭显示器: When close lid: 关闭笔记本电脑上盖时: Screen darkens use battery: 无操作状态下于此时间后减小屏幕亮度: Power Other Settings 电源图标设置 S3 to S4 when: 挂起此时间后转为睡眠: Power Icon Settings 电源图标设置 Power icon: 电源图标: power 电源 Power ھوقۇق Change PC sleep time after %1 min: 系统%1分钟后进入空闲状态并于此时间后挂起: Change DP close time after %1 min: 系统%1分钟后进入空闲状态并于此时间后关闭显示器: Enter idle state %1 min and sleep after %2 min : 系统%1分钟后进入空闲状态并于%2分钟后挂起: Enter idle state %1 min and close after %2 min : 系统%1分钟后进入空闲状态并于%2分钟后关闭显示器: never مەڭگۈ 10 min 10分钟 30 min 30分钟 60 min 60分钟 120 min 120分钟 300 min 300分钟 20 min 20分钟 1 min 1分钟 5 min 5分钟 Require password when suspend/hibernation ئۇيقۇ/ئۇيقۇ ھالىتىدە مەخپىي نومۇر تەلەپ قىلىش Require password when suspend Require password when suspend/hibernate /Power/Require password when suspend/hibernate The system will sleep before turning off the display Reduce the occupation of backend running program resources and ensure smooth operation of key and focus applications. Battery Maximum Capacity باتارېيەنىڭ ئەڭ چوڭ سىغىمى This is the battery capacity relative to a new battery. A lower capacity may result in a shorter battery life after charging. بۇ يېڭى باتارېيەگە نىسبەتەن، باتارېيە سىغىمى سىغىمى تۆۋەن بولسا زەرەتلىگەندىن كېيىن باتارېيەنىڭ ئۆمرى قىسقارتىشى مۇمكىن. The battery capacity is low, please replace the battery. باتارېيە سىغىمى تۆۋەن، باتارىيىنى ئالماشتۇرۇڭ. Unable to obtain battery capacity, please contact the hardware manufacturer for repair. باتارېيە سىغىمىغا ئېرىشەلمىسە، قاتتىق دېتال زاۋۇتى بىلەن ئالاقىلىشىڭ. Require password when hibernate Password required when waking up the screen ئېكراننى ئويغىتىشتا زۆرۈر بولغان پارول /Power/Password required when waking up the screen Press the power button توك كۇنۇپكىسىنى بېسىش /Power/Press the power button Time to close display كۆرسىتىشنى تاقاش ۋاقتى /Power/Time to close display Time to sleep ئۇخلاش ۋاقتى /Power/Time to sleep After this period, the system will transition from sleep to hibernation. بۇ ۋاقىتتىن كېيىن سىستېما ئۇيقۇ ھالىتىدىن ئۇيقۇغا ئۆتىدۇ. /Power/Time to hibernate Power plan توك قۇۋۋەت پىلانى /Power/Using battery Notebook cover خاتىرە كومپىيۇتېر مۇقاۋىسى /Power/Notebook cover Host light strip /Power/Host light strip Dynamic resource scheduling /Power/Dynamic resource scheduling Display remaining charging and discharging time قالدۇق زەرەتلەش ۋە توك چىقىرىش ۋاقتىنى كۆرسىتىش Using power توك ئىشلىتىش /Power/Using power Using battery باتارېيە ئىشلىتىش /Power/Using battery Time to darken قاراڭغۇلۇققا پاتىدىغان ۋاقىت Battery level is lower than باتارېيە دەرىجىسى ئۇنىڭدىن تۆۋەن Run يۈگۈرۈش Low battery notification باتارېيە مىقدارى تۆۋەن بولۇش ئۇقتۇرۇشى /Power/Low battery notification Automatically run saving mode when low battery باتارېيە ئاز بولغاندا تېجەش ھالىتىنى ئاپتوماتىك ئىجرا قىلىش /Power/"Automatically run saving mode when low battery Automatically run saving mode when the low battery باتارىيە تۆۋەن بولغاندا تىجەش ھالىتىنى ئاپتوماتىك ئىجرا قىلىش Automatically run saving mode when using battery باتارىيە ئىشلەتكەندە تېجەش ھالىتىنى ئاپتوماتىك ئىجرا قىلىش Display remaining charging time and usage time ئېشىپ قالغان توك قاچىلاش ۋاقتى ۋە ئىشلىتىش ۋاقتىنى كۆرسىتىش Nothing Blank Shutdown 关机 Suspend Hibernate Interactive General ارينا /Power/General using AC power using battery Select Powerplan Powerplan تاللاش /Power/Select Powerplan Battery saving plan باتارېيە تېجەش پىلانى /Power/Battery saving plan nothing ھېچنېمە blank قۇرۇق suspend توختىتىپ قويۇش hibernate hibernate interactive ئۆز ئارا تەسىرلىشىش 5min 5min 4h 5h Balance 声道平衡 Energy Efficiency Performance ئويۇن قويۇش Performance Model ئىقتىدار ئۈلگىسى 20min 20min 10minn 10分钟 15min 15min 30min 30min 1h 2h 10min 10min Never مەڭگۈ 100min 3分钟 {100m?} 3h Balance Model تەڭپۇڭلۇق مودېلى Save Model مودېلنى ساقلاش 1min 1min 3min 3分钟 shutdown تاقاش always 显示电源图标在托盘栏 present 仅当存在电池时显示 charge 仅当使用电池时显示 Perform operations when battery is low: 低电量执行操作: General Settings 通用设置 When the power button is pressed: 按电源键时执行: ukui-power-manager/power/translations/bo_CN.ts0000664000175000017500000007166015167661430020447 0ustar fengfeng Power Power གློག་ཁུངས། The system will sleep before turning off the display མ་ལག་གི་སྒོ་རྒྱག་འཆར་ཆས་གོང་ལ་གཉིད་། Reduce the occupation of backend running program resources and ensure smooth operation of key and focus applications. རྒྱབ་སྟེགས་འཁོར་རྒྱུག་གོ་རིམ་གྱི་ཐོན་ཁུངས་བཟུང་སྤྱོད་ཉུང་དུ་གཏོང་བ།འགག་རྩའི་བཀོལ་སྤྱོད་དང་མདོ་གནད་བཀོལ་སྤྱོད་བདེ་བླག་ཡོང་བའི་འགན་ལེན་བཅས་བྱེད་དགོས། Battery Maximum Capacity གློག་སྨན་གྱི་ཤོང་ཚད་ཆེས་ཆེ་བ། Require password when suspend གཉིད་ཉལ་སྐབས་གསང་གྲངས་དགོས་ Require password when suspend/hibernate གཉིད་དང་གཉིད།གཉིད།གཉིད་སད་པའི་རྗེས་ནས་གསང་གྲངས་ /Power/Require password when suspend/hibernate Require password when hibernate གཉིད་ལས་བསད་པར་གསང་གྲངས་དགོས། never གཏན་ནས་བྱེད་མི་ Require password when suspend/hibernation གཉིད་ཉལ་སྐབས་གསང་གྲངས་དགོས་པའི་བླང་བྱ་བཏོན་ཡོད། Password required when waking up the screen བརྙན་ཤེལ་གཉིད་ལས་སད་སྐབས་མཁོ་བའི་གསང་གྲངས། /Power/Password required when waking up the screen Press the power button གློག་ཁུངས།་ཀྱི་མཐེབ་གཅུས་ /Power/Press the power button Time to close display འགྲེམས་སྟོན་མཇུག་སྒྲིལ་བའི་དུས་ཚོད། /Power/Time to close display Time to sleep གཉིད་ཉལ་བའི་དུས་ཚོད། /Power/Time to sleep After this period, the system will transition from sleep to hibernation. དུས་ཚོད་འདི་གི་རྗེས་སྤྱོད་རིམ་ལས་མ་ལུས་པའི་སྒོ་ནས་མི་རིམ་ལས་སྒོ་རྒྱག་གི་རེད། /Power/Time to hibernate Power plan ནུས་བརྡ་ལས་རིམ། /Power/Using battery Notebook cover ཟིན་བྲིས་ཀྱི་ཁེབས་རས། /Power/Notebook cover Dynamic resource scheduling ཐོན་ཁུངས་འགུལ་རྣམ་བཀོད་གཏོང་ /Power/Dynamic resource scheduling Display remaining charging and discharging time གནས་ལུས་གློག་གསོག་དང་གློག་འདོན་དུས་ཚོད་འཆར་བ། Using power དབང་ཆ་བེད་སྤྱོད་བྱ་དགོས། /Power/Using power Using battery གློག་སྨན་བཀོལ་སྤྱོད་བྱེད་པ། /Power/Using battery Time to darken མུན་ནག་ཏུ་འགྱུར་བའི་དུས་ཚོད། Battery level is lower than གློག་གཡིས་ཀྱི་ཆུ་ཚད་ལས་དམའ་བ། Run འཁོར་སྐྱོད་བྱེད་བཞིན་ Low battery notification གློག་གཡིས་ཀྱི་བརྡ་ཐོ་དམའ་བ། /Power/Low battery notification Automatically run saving mode when low battery གློག་གཡིས་དམའ་བའི་དུས་སུ་རང་འགུལ་གྱིས་གྲོན་ཆུང་བྱེད་ཐབས་ /Power/"Automatically run saving mode when low battery Automatically run saving mode when the low battery གློག་སྨན་དམའ་བའི་སྐབས་སུ་རང་འགུལ་གྱིས་གྲོན་ཆུང་བྱེད་སྟངས་འཁོར་སྐྱོད་ Automatically run saving mode when using battery གློག་གཡིས་བཀོལ་སྤྱོད་བྱེད་སྐབས་རང་འགུལ་གྱིས་གྲོན་ཆུང་བྱེད་སྟངས་བཀོལ Display remaining charging time and usage time དེ་བྱིངས་ཀྱི་གློག་གསོག་དུས་ཚོད་དང་བཀོལ་སྤྱོད་ཀྱི་དུས་ཚོད་མངོན་པར་བྱས་ཡོད། Nothing ཅི་ཡང་མ་རེད། Blank སྟོང་ཆ། Shutdown ཁ་རྒྱག Suspend གཉིད་ Hibernate མངལ་གནས་སུ་སྦས་པ། Interactive ཕན་ཚུན་སྐུལ་འདེད་ General ཐུན་མོང་དུ་སྤྱོད་པ། /Power/General using AC power using battery Select Powerplan གློག་ཁུངས།་འཆར་གཞི་བདམས་པ། /Power/Select Powerplan Battery saving plan གློག་གཡིས་གྲོན་ཆུང་གི་འཆར་ /Power/Battery saving plan This is the battery capacity relative to a new battery. A lower capacity may result in a shorter battery life after charging. འདི་ནི་གློག་སྨན་གསར་བའི་གློག་སྨན་གྱི་ཤོང་ཚད་ཡིན། ཤོང་ཚད་ཅུང་དམའ་བས་གློག་གསོག་རྗེས་ཀྱི་གློག་སྨན་གྱི་ཚེ་ཚད་ཇེ་ཐུང་དུ་འགྲོ་སྲིད། The battery capacity is low, please replace the battery. གློག་སྨན་གྱི་ཤོང་ཚད་དམའ་བས་གློག་སྨན་བརྗེ་རོགས། Unable to obtain battery capacity, please contact the hardware manufacturer for repair. གློག་སྨན་གྱི་ཤོང་ཚད་ལེན་ཐབས་མེད་པས་མཁྲེགས་ཆས་བཟོ་མཁན་དང་འབྲེལ་བ་བྱས་ནས་ཞིག་གསོ་བྱེད་རོགས། Host light strip གློག་སྒྲོན་གཙོ་བོ། /Power/Host light strip nothing ཅི་ཡང་མ་རེད། blank སྟོང་ཆ། suspend གཉིད་ hibernate མངལ་གནས་སུ་སྦས་པ། interactive ཕན་ཚུན་སྐུལ་འདེད་ 5min 5སྐར་མ་ 10min 10སྐར་མ་ 15min 15སྐར་མ་ 30min 30སྐར་མ་ 1h 1ཆུ་ཚོད། 2h 2ཆུ་ཚོད། Never གཏན་ནས་བྱེད་མི་ 100min 20min {100m?} 3h 3ཆུ་ཚོད། 4h 4ཆུ་ཚོད། 5h 5ཆུ་ཚོད། Balance དོ་མཉམ། Energy Efficiency ཕན་འབྲས་ལེགས་ཤོས་ Performance མཆོག་གྱུར་གཤིས་ནུས། Balance Model དོ་མཉམ་གྱི་དཔེ་དབྱིབས། Save Model གསོག་འཇོག་བྱེད་སྟངས། Performance Model གྲུབ་འབྲས་ཀྱི་དཔེ་དབྱིབས། 1min སྐར་མ་གཅིག་གི་རིང་། 20min 20min shutdown ཁ་རྒྱག ukui-power-manager/power/translations/mn.ts0000664000175000017500000010226415167661430020074 0ustar fengfeng Power select power plan 电源计划 Balance (suggest) 平衡(推荐) Saving 节能 Minimize performance 尽可能降低计算机能耗 Bala&nce (suggest) Autobalance energy and performance with available hardware 利用可用的硬件自动平衡消耗与性能 Custom 自定义 Users develop personalized power plans 用户制定个性化电源计划 Power supply 电源供给 Battery powered 电池供给 Change PC sleep time: 系统进入空闲状态并于此时间后睡眠: Change DP close time: 系统进入空闲状态并于此时间后关闭显示器: Change pc sleep time: 系统进入空闲状态并于此时间后挂起: Change dp close time: 系统进入空闲状态并于此时间后关闭显示器: When close lid: 关闭笔记本电脑上盖时: Screen darkens use battery: 无操作状态下于此时间后减小屏幕亮度: Power Other Settings 电源图标设置 S3 to S4 when: 挂起此时间后转为睡眠: Power Icon Settings 电源图标设置 Power icon: 电源图标: power 电源 Power ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠭᠡᠭᠴᠢ Change PC sleep time after %1 min: 系统%1分钟后进入空闲状态并于此时间后挂起: Change DP close time after %1 min: 系统%1分钟后进入空闲状态并于此时间后关闭显示器: Enter idle state %1 min and sleep after %2 min : 系统%1分钟后进入空闲状态并于%2分钟后挂起: Enter idle state %1 min and close after %2 min : 系统%1分钟后进入空闲状态并于%2分钟后关闭显示器: never 从不 10 min 10分钟 30 min 30分钟 60 min 60分钟 120 min 120分钟 300 min 300分钟 20 min 20分钟 1 min 1分钟 5 min 5分钟 Require password when suspend/hibernation 睡眠/休眠唤醒时需要密码 The system will sleep before turning off the display ᠰᠢᠰᠲ᠋ᠧᠮ ᠨᠢ ᠦᠵᠡᠭᠦᠷ᠎ᠢ᠋ ᠬᠠᠭᠠᠬᠤ ᠡᠴᠡ ᠡᠮᠦᠨ᠎ᠡ ᠤᠨᠲᠠᠬᠤ ᠪᠣᠯᠤᠨ᠎ᠠ Require password when suspend Require password when suspend/hibernate ᠤᠨᠲᠠᠬᠤ ᠪᠠᠨ ᠲᠦᠷ ᠵᠣᠭᠰᠣᠬᠤ ᠦᠶᠡᠰ ᠨᠢᠭᠤᠴᠠ ᠨᠣᠮᠧᠷ ᠬᠡᠷᠡᠭᠰᠡᠨ᠎ᠡ ᠃ /Power/Require password when suspend/hibernate Reduce the occupation of backend running program resources and ensure smooth operation of key and focus applications. ᠠᠷᠤ ᠲᠠᠪᠴᠠᠩ᠎ᠤ᠋ᠨ ᠠᠵᠢᠯᠯᠠᠭᠠᠨ᠎ᠤ᠋ ᠳᠡᠰ ᠳᠠᠷᠠᠭᠠᠯᠠᠯ᠎ᠤ᠋ᠨ ᠡᠬᠢ ᠪᠠᠶᠠᠯᠢᠭ᠎ᠢ᠋ ᠡᠵᠡᠯᠡᠬᠦ᠎ᠶ᠋ᠢ ᠪᠠᠭᠠᠰᠬᠠᠵᠤ ᠂ ᠵᠠᠩᠭᠢᠯᠠᠭ᠎ᠠ᠎ᠶ᠋ᠢᠨ ᠬᠡᠷᠡᠭᠯᠡᠭᠡ ᠬᠢᠭᠡᠳ ᠲᠥᠪᠯᠡᠷᠡᠯ᠎ᠦ᠋ᠨ ᠴᠢᠭ᠎ᠦ᠋ᠨ ᠬᠡᠷᠡᠭᠯᠡᠭᠡᠨ᠎ᠦ᠌ ᠤᠷᠤᠰᠬᠠᠯ᠎ᠲᠠᠢ ᠤᠷᠤᠭᠰᠢᠲᠠᠢ ᠶᠠᠪᠤᠭᠳᠠᠬᠤ᠎ᠶ᠋ᠢ ᠪᠠᠲᠤᠯᠠᠬᠤ ᠬᠡᠷᠡᠭᠲᠡᠢ using AC power using battery Require password when hibernate ᠢᠴᠡᠭᠡᠯᠡᠭᠰᠡᠨ᠎ᠦ᠌ ᠳᠠᠷᠠᠭ᠎ᠠ ᠳᠠᠭᠤᠳᠠᠨ ᠰᠡᠷᠡᠭᠡᠬᠦ᠎ᠳ᠋ᠦ᠍ ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠬᠡᠷᠡᠭᠲᠡᠢ Password required when waking up the screen ᠳᠡᠯᠭᠡᠴᠡ᠎ᠶ᠋ᠢ ᠳᠠᠭᠤᠳᠠᠨ ᠰᠡᠷᠭᠦᠭᠡᠬᠦ ᠦᠶᠡᠰ ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋ ᠬᠡᠷᠡᠭᠰᠡᠨ᠎ᠡ /Power/Password required when waking up the screen Press the power button ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠬᠡᠭᠦᠷ᠎ᠦ᠋ᠨ ᠳᠠᠷᠤᠪᠴᠢ᠎ᠶ᠋ᠢ ᠳᠠᠷᠤᠬᠤ ᠦᠶᠡᠰ ᠭᠦᠢᠴᠡᠳᠬᠡᠬᠦ /Power/Press the power button Time to close display ᠡᠨᠡ ᠴᠠᠭ᠎ᠤ᠋ᠨ ᠬᠡᠰᠡᠭ᠎ᠦ᠋ᠨ ᠬᠣᠢᠨ᠎ᠠ ᠦᠵᠡᠭᠦᠷ᠎ᠢ᠋ ᠬᠠᠭᠠᠬᠤ /Power/Time to close display Time to sleep ᠲᠤᠰ ᠴᠠᠭ᠎ᠤ᠋ᠨ ᠬᠡᠰᠡᠭ ᠤ᠋ᠨ ᠳᠠᠷᠠᠭ᠎ᠠ ᠰᠢᠰᠲ᠋ᠧᠮ ᠨᠢ ᠤᠨᠳᠠᠬᠤ ᠪᠤᠯᠤᠨ᠎ᠠ /Power/Time to sleep After this period, the system will transition from sleep to hibernation. Энэ хугацааны дараа систем унтлагын горимоос амралтын горимд шилжинэ. /Power/Time to hibernate Power plan Цахилгаан төлөвлөгөө /Power/Using battery Notebook cover ᠭᠠᠷ ᠺᠤᠮᠫᠢᠦ᠋ᠲᠸᠷ ᠬᠠᠭᠠᠬᠤ᠎ᠳ᠋ᠤ᠌ ᠭᠦᠢᠴᠡᠳᠬᠡᠬᠦ /Power/Notebook cover Host light strip /Power/Host light strip Dynamic resource scheduling ᠡᠬᠢ ᠪᠠᠶᠠᠯᠢᠭ᠎ᠤ᠋ᠨ ᠬᠥᠳᠡᠯᠦᠩᠭᠦᠢ ᠲᠣᠬᠢᠷᠠᠭᠤᠯᠤᠯᠲᠠ /Power/Dynamic resource scheduling Display remaining charging and discharging time Үлдсэн цэнэглэлт ба цэнэггүйжүүлэх хугацааг харуулах Using power ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠬᠡᠭᠦᠷ᠎ᠦ᠋ᠨ ᠴᠠᠭ᠎ᠢ᠋ ᠬᠡᠷᠡᠭᠯᠡᠬᠦ /Power/Using power Using battery ᠳ᠋ᠢᠶᠠᠨ ᡂᠢ ᠢ᠋ ᠬᠡᠷᠡᠭᠯᠡᠬᠦ ᠦᠶᠡᠰ /Power/Using battery Time to darken ᠲᠤᠰ ᠴᠠᠭ᠎ᠤ᠋ᠨ ᠬᠡᠰᠡᠭ ᠤ᠋ᠨ ᠳᠠᠷᠠᠭ᠎ᠠ ᠳᠡᠯᠭᠡᠴᠡ᠎ᠶ᠋ᠢᠨ ᠭᠡᠷᠡᠯᠲᠦᠴᠡ᠎ᠶ᠋ᠢ ᠪᠠᠭᠤᠷᠠᠭᠤᠯᠬᠤ Battery level is lower than ᠴᠡᠨᠡᠭ ᠳᠣᠣᠷ᠎ᠠ Run ᠠᠵᠢᠯᠯᠠᠭᠠᠨ Low battery notification ᠴᠡᠨᠡᠭ ᠳᠤᠤᠷ᠎ᠠ ᠦᠶ᠎ᠡ ᠳ᠋ᠤ᠌ ᠮᠡᠳᠡᠭᠳᠡᠬᠦ /Power/Low battery notification Automatically run saving mode when low battery ᠴᠡᠨᠡᠭ ᠳᠤᠤᠷ᠎ᠠ ᠦᠶᠡᠰ ᠡᠨᠧᠷᠭᠢ ᠠᠷᠪᠢᠯᠠᠬᠤ ᠵᠠᠭᠪᠤᠷ᠎ᠢ᠋ ᠠᠦ᠋ᠲ᠋ᠣ᠋ ᠪᠡᠷ ᠨᠡᠭᠡᠭᠡᠬᠦ /Power/"Automatically run saving mode when low battery Automatically run saving mode when the low battery ᠴᠡᠨᠡᠭ ᠳᠣᠣᠷ᠎ᠠ ᠦᠶᠡᠰ ᠡᠨᠧᠷᠭᠢ ᠠᠷᠪᠢᠯᠠᠬᠤ ᠵᠠᠭᠪᠤᠷ᠎ᠢ᠋ ᠠᠦ᠋ᠲ᠋ᠣ᠋ ᠪᠡᠷ ᠨᠡᠭᠡᠭᠡᠬᠦ Automatically run saving mode when using battery ᠳ᠋ᠢᠶᠠᠨ ᡂᠢ ᠬᠡᠷᠡᠭᠯᠡᠬᠦ ᠦᠶᠡᠰ ᠡᠨᠧᠷᠭᠢ ᠬᠡᠮᠨᠡᠬᠦ ᠵᠠᠭᠪᠤᠷ᠎ᠢ᠋ ᠠᠦ᠋ᠲ᠋ᠣ᠋ ᠪᠡᠷ ᠨᠡᠭᠡᠭᠡᠬᠦ Display remaining charging time and usage time ᠦᠯᠡᠳᠡᠪᠦᠷᠢ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠴᠡᠨᠡᠭᠯᠡᠬᠦ ᠴᠠᠭ ᠪᠠ ᠦᠯᠡᠳᠡᠪᠦᠷᠢ ᠬᠡᠷᠡᠭᠯᠡᠬᠦ ᠴᠠᠭ᠎ᠢ᠋ ᠢᠯᠡᠷᠡᠭᠦᠯᠬᠦ Nothing ᠦᠭᠡᠢ Blank Shutdown ᠪᠠᠶᠢᠭᠤᠯᠤᠯᠭ᠎ᠠ ᠶᠢᠨ ᠳᠠᠪᠲᠠᠮᠵᠢ Suspend ᠵᠤᠭ᠍ᠰᠤᠭᠠᠬᠤ Hibernate ᠢᠴᠡᠬᠡᠯᠡᠬᠦ᠌ Interactive ᠠᠰᠠᠭᠤᠨ ᠯᠠᠪᠯᠠᠭ᠎ᠠ General ᠳᠦᠷᠢᠮᠵᠢᠯ /Power/General Select Powerplan ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠬᠡᠭᠦᠷ᠎ᠦ᠋ᠨ ᠲᠥᠯᠥᠪᠯᠡᠭᠡ /Power/Select Powerplan Battery saving plan ᠳ᠋ᠢᠶᠠᠨ ᡂᠢ᠎ᠶ᠋ᠢᠨ ᠡᠨᠧᠷᠭᠢ ᠬᠡᠮᠨᠡᠬᠦ ᠲᠥᠯᠥᠪᠯᠡᠭᠡ /Power/Battery saving plan nothing 无操作 blank 关闭显示器 suspend 睡眠 hibernate 休眠 interactive 询问 5min 5 ᠮᠢᠨᠦ᠋ᠲ 4h 4 ᠴᠠᠭ 5h 5 ᠴᠠᠭ Balance ᠲᠡᠩᠴᠡᠭᠦᠷᠢ Energy Efficiency ᠬᠠᠮᠤᠭ ᠰᠠᠢᠨ ᠡᠨᠧᠷᠭᠢ᠎ᠶ᠋ᠢᠨ ᠠᠰᠢᠭᠯᠠᠮᠵᠢ Performance ᠴᠢᠳᠠᠪᠬᠢ ᠵᠢᠨ ᠵᠠᠭᠪᠤᠷ Performance Model 性能模式 20min 20分钟 10minn 10分钟 15min 15 ᠮᠢᠨᠦ᠋ᠲ 30min 30 ᠮᠢᠨᠦ᠋ᠲ 1h 1 ᠴᠠᠭ 2h 2 ᠴᠠᠭ 10min 10 ᠮᠢᠨᠦ᠋ᠲ Never ᠯᠠᠪᠳᠠᠢ ᠪᠢᠰᠢ 100min 3分钟 {100m?} 3h 3 ᠴᠠᠭ Balance Model 平衡模式 Save Model 节能模式 1min 1 ᠮᠢᠨᠦ᠋ᠲ 3min 3分钟 shutdown 关机 always 显示电源图标在托盘栏 present 仅当存在电池时显示 charge 仅当使用电池时显示 Perform operations when battery is low: 低电量执行操作: General Settings 通用设置 When the power button is pressed: 按电源键时执行: ukui-power-manager/power/translations/en_US.ts0000664000175000017500000005642115167661430020476 0ustar fengfeng Power Power The system will sleep before turning off the display Reduce the occupation of backend running program resources and ensure smooth operation of key and focus applications. Battery Maximum Capacity Battery Maximum Capacity Require password when suspend/hibernate /Power/Require password when suspend/hibernate Require password when suspend Require password when hibernate Password required when waking up the screen /Power/Password required when waking up the screen Press the power button /Power/Press the power button Time to close display /Power/Time to close display Time to sleep /Power/Time to sleep After this period, the system will transition from sleep to hibernation. /Power/Time to hibernate Power plan Power Plan /Power/Using battery Notebook cover /Power/Notebook cover Host light strip /Power/Host light strip Dynamic resource scheduling /Power/Dynamic resource scheduling Display remaining charging and discharging time Using power /Power/Using power Using battery /Power/Using battery Time to darken Battery level is lower than Run Low battery notification /Power/Low battery notification Automatically run saving mode when low battery /Power/"Automatically run saving mode when low battery Automatically run saving mode when the low battery Automatically run saving mode when using battery Display remaining charging time and usage time Nothing Blank Shutdown Suspend Hibernate Interactive Never General /Power/General using AC power using battery Select Powerplan /Power/Select Powerplan Battery saving plan /Power/Battery saving plan This is the battery capacity relative to a new battery. A lower capacity may result in a shorter battery life after charging. This is the battery capacity relative to a new battery. A lower capacity may result in a shorter battery life after charging. The battery capacity is low, please replace the battery. The battery capacity is low, please replace the battery. Unable to obtain battery capacity, please contact the hardware manufacturer for repair. Unable to obtain battery capacity, please contact the hardware manufacturer for repair. 5min 10min 15min 30min 1h 2h 1min 3h 4h 5h Balance Energy Efficiency Performance ukui-power-manager/power/translations/zh_HK.ts0000664000175000017500000007644415167661430020477 0ustar fengfeng Power select power plan 电源计划 Balance (suggest) 平衡(推荐) Saving 节能 Minimize performance 尽可能降低计算机能耗 Bala&nce (suggest) Autobalance energy and performance with available hardware 利用可用的硬件自动平衡消耗与性能 Custom 自定义 Users develop personalized power plans 用户制定个性化电源计划 Power supply 电源供给 Battery powered 电池供给 Change PC sleep time: 系统进入空闲状态并于此时间後睡眠: Change DP close time: 系统进入空闲状态并于此时间後关闭显示器: Change pc sleep time: 系统进入空闲状态并于此时间後挂起: Change dp close time: 系统进入空闲状态并于此时间後关闭显示器: When close lid: 关闭笔记本电脑上盖时: Screen darkens use battery: 无操作状态下于此时间後减小屏幕亮度: Power Other Settings 电源图标设置 S3 to S4 when: 挂起此时间後转为睡眠: Power Icon Settings 电源图标设置 Power icon: 电源图标: power 电源 Power 電源 Change PC sleep time after %1 min: 系统%1分钟後进入空闲状态并于此时间後挂起: Change DP close time after %1 min: 系统%1分钟後进入空闲状态并于此时间後关闭显示器: Enter idle state %1 min and sleep after %2 min : 系统%1分钟後进入空闲状态并于%2分钟後挂起: Enter idle state %1 min and close after %2 min : 系统%1分钟後进入空闲状态并于%2分钟後关闭显示器: never 從不 10 min 10分钟 30 min 30分钟 60 min 60分钟 120 min 120分钟 300 min 300分钟 20 min 20分钟 1 min 1分钟 5 min 5分钟 Require password when sleep/hibernation 睡眠/休眠唤醒时需要密码 The system will sleep before turning off the display 系統將在關閉顯示器之前進入睡眠 Require password when sleep 睡眠後喚醒需要密碼 Require password when sleep/hibernate 睡眠/休眠後喚醒需要密碼 Reduce the occupation of backend running program resources and ensure smooth operation of key and focus applications. 減少後台運行程序資源佔用,保障關鍵應用與焦點應用流暢運行。 Battery Maximum Capacity 電池最大容量 This is the battery capacity relative to a new battery. A lower capacity may result in a shorter battery life after charging. 這是相對於新電池的電池容量。 較低的容量可能會導致充電後電池壽命縮短。 The battery capacity is low, please replace the battery. 電池電量低,請更換電池。 Unable to obtain battery capacity, please contact the hardware manufacturer for repair. 無法獲取電池容量,請聯系硬體製造商進行維修。 Require password when suspend/hibernate 睡眠/休眠後喚醒需要密碼 /Power/Require password when suspend/hibernate Require password when suspend 睡眠後喚醒需要密碼 Require password when hibernate 休眠後喚醒需要密碼 Password required when waking up the screen 喚醒螢幕時需要密碼 /Power/Password required when waking up the screen Press the power button 按電源鍵時執行 /Power/Press the power button Time to close display 此時間段後關閉顯示器 /Power/Time to close display Time to sleep 此時間段後系統進入睡眠 /Power/Time to sleep After this period, the system will transition from sleep to hibernation. 此時間段後系統由睡眠進入休眠 /Power/Time to hibernate Power plan 電源計劃 /Power/Using battery Notebook cover 筆記本合蓋時執行 /Power/Notebook cover Host light strip 主機燈帶 /Power/Host light strip Dynamic resource scheduling 資源動態調度 /Power/Dynamic resource scheduling Display remaining charging and discharging time 顯示剩餘充電和放電時間 Using power 使用電源時 /Power/Using power Using battery 使用電池時 /Power/Using battery Time to darken 此時間段後降低螢幕亮度 Battery level is lower than 電量低於 Run 時執行 Low battery notification 低電量時通知 /Power/Low battery notification Automatically run saving mode when low battery 低電量時自動開啟節能模式 /Power/"Automatically run saving mode when low battery Automatically run saving mode when the low battery 低電量時自動開啟節能模式 Automatically run saving mode when using battery 使用電池時自動開啟節能模式 Display remaining charging time and usage time 顯示剩餘充電時間和剩餘使用時間 Nothing 無操作 Blank 關閉顯示器 Shutdown 關機 Suspend 睡眠 Hibernate 休眠 Interactive 詢問 General 通用 /Power/General using AC power using battery Select Powerplan 電源計劃 /Power/Select Powerplan Battery saving plan 電池節能計劃 /Power/Battery saving plan nothing 無操作 blank 關閉顯示器 suspend 睡眠 hibernate 休眠 interactive 詢問 5min 5 分鐘 4h 4 小時 5h 5 小時 Balance 平衡 Energy Efficiency 最佳能效 Performance 最佳性能 Performance Model 性能模式 20min 20分钟 10minn 10分钟 15min 15 分鐘 30min 30 分鐘 1h 1 小時 2h 2 小時 10min 10 分鐘 Never 從不 100min 3分钟 {100m?} 3h 3 小時 Balance Model 平衡模式 Save Model 节能模式 1min 1 分鐘 3min 3分钟 shutdown 關機 always 显示电源图标在托盘栏 present 仅当存在电池时显示 charge 仅当使用电池时显示 Perform operations when battery is low: 低电量执行操作: General Settings 通用设置 When the power button is pressed: 按电源键时执行: ukui-power-manager/power/power.cpp0000664000175000017500000020345215167661430016232 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "power.h" #include "powermacrodata.h" #include #include #include #include #include #include #include #include #include "ukcccommon.h" using namespace ukcc; /* qt会将glib里的signals成员识别为宏,所以取消该宏 * 后面如果用到signals时,使用Q_SIGNALS代替即可 **/ #ifdef signals #undef signals #endif #include "libupower-glib/upower.h" typedef enum { BALANCE, SAVING, CUSTDOM }MODE; #define DISPLAY_BALANCE_BA 5 * 60 #define DISPLAY_BALANCE_AC 10 * 60 #define COMPUTER_BALANCE_BA 5 * 60 #define COMPUTER_BALANCE_AC 10 * 60 #define BRIGHTNESS_BALANCE 100 #define DISPLAY_SAVING 60 #define COMPUTER_SAVING 2 * 60 #define BRIGHTNESS_SAVING 20 int closeArray[7] = {5, 10, 15, 30, 60, 120, 0}; Power::Power() : mFirstLoad(true) { QTranslator *translator = new QTranslator(this); if (translator->load(QString(QM_FILES_INSTALL_PATH) + QLocale::system().name())) { QApplication::installTranslator(translator); } else { qWarning() << "load power qm file error"; } pluginName = tr("Power"); pluginType = SYSTEM; initInterface(); } Power::~Power() { if (!mFirstLoad) { } } QString Power::plugini18nName() { return pluginName; } int Power::pluginTypes() { return pluginType; } QWidget * Power::pluginUi() { if (mFirstLoad) { pluginWidget = new QWidget; pluginWidget->setAttribute(Qt::WA_DeleteOnClose); const QByteArray styleID(STYLE_FONT_SCHEMA); const QByteArray id(POWERMANAGER_SCHEMA); const QByteArray iid(SESSION_SCHEMA); const QByteArray iiid(SCREENSAVER_SCHEMA); const QByteArray IVd(PERSONALSIE_SCHEMA); const QByteArray Vd(UKUI_QUICK_OPERATION_PANEL); const QByteArray procID(PROC_MANAGER); if (QGSettings::isSchemaInstalled(procID)) { mProcManagerSettings = new QGSettings(procID, QByteArray(), this); } if (QGSettings::isSchemaInstalled(id) && QGSettings::isSchemaInstalled(styleID) && QGSettings::isSchemaInstalled(iid) && QGSettings::isSchemaInstalled(iiid) && QGSettings::isSchemaInstalled(IVd) ) { settings = new QGSettings(id, QByteArray(), this); stylesettings = new QGSettings(styleID, QByteArray(), this); sessionsettings = new QGSettings(iid, QByteArray(), this); screensettings = new QGSettings(iiid, QByteArray(), this); m_centerSettings = new QGSettings(IVd,QByteArray(), this); if (QGSettings::isSchemaInstalled(Vd) && UkccCommon::isTablet()) { m_qsettings = new QGSettings(Vd,QByteArray(), this); } else { m_qsettings = nullptr; } connect(stylesettings,&QGSettings::changed,[=](QString key) { if("systemFont" == key || "systemFontSize" == key) { retranslateUi(); } }); mKeys = settings->keys(); hostLightStripDbus = new QDBusInterface("com.control.center.qt.systemdbus", "/", "com.control.center.interface", QDBusConnection::systemBus(), this); if (!hostLightStripDbus->isValid()){ qCritical() << "Create Client Interface Failed:" << QDBusConnection::systemBus().lastError(); } else { QDBusReply ret = hostLightStripDbus->call("isSupportHostLightStrip"); isSupportHostLight = ret; } isExitBattery(); initUI(pluginWidget); isLidPresent(); setupComponent(); initCustomPlanStatus(); setupConnect(); resetui(); hideComponent(); hideComponentByConf2(); } } return pluginWidget; } const QString Power::name() const { return QStringLiteral("Power"); } bool Power::isShowOnHomePage() const { return true; } QIcon Power::icon() const { return QIcon::fromTheme("system-shutdown-symbolic"); } bool Power::isEnable() const { return true; } void Power::initUI(QWidget *widget) { // 整体布局 mverticalLayout = new QVBoxLayout(widget); mverticalLayout->setSpacing(8); mverticalLayout->setContentsMargins(0, 0, 0, 0); m_customTitleLabel = new KLabel(widget); m_customTitleLabel->setContentsMargins(16, 0, 0, 0); //~ contents_path /Power/General m_customTitleLabel->setText(tr("General")); mverticalLayout->addWidget(m_customTitleLabel); // 通用设置布局 Powerwidget = new QFrame(widget); Powerwidget->setMinimumSize(QSize(550, 0)); Powerwidget->setMaximumSize(QSize(16777215, 16777215)); Powerwidget->setFrameShape(QFrame::Box); PowerLayout = new QVBoxLayout(Powerwidget); PowerLayout->setContentsMargins(0, 0, 0, 0); PowerLayout->setSpacing(0); mSleepPwdFrame = new QFrame(Powerwidget); setFrame_Noframe(mSleepPwdFrame); QHBoxLayout *mSleepPwdLayout = new QHBoxLayout(mSleepPwdFrame); mSleepPwdLayout->setContentsMargins(16, 0, 16, 0); mSleepPwdLabel = new QLabel(mSleepPwdFrame); mSleepPwdLabel->setFixedSize(550,60); mSleepPwdBtn = new KSwitchButton(mSleepPwdFrame); QSize size1 = mSleepPwdBtn->size(); qDebug() << "mSleepPwdBtn size:" << size1.width() << "x" << size1.height(); mSleepPwdBtn->setObjectName("sleepwaken"); mSleepPwdLayout->addWidget(mSleepPwdLabel); mSleepPwdLayout->addStretch(); mSleepPwdLayout->addWidget(mSleepPwdBtn); PowerLayout->addWidget(mSleepPwdFrame); line_1 = setLine(Powerwidget); PowerLayout->addWidget(line_1); mWakenPwdFrame = new QFrame(Powerwidget); setFrame_Noframe(mWakenPwdFrame); QHBoxLayout *mWakenPwdLayout = new QHBoxLayout(mWakenPwdFrame); mWakenPwdLayout->setContentsMargins(16, 0, 16, 0); mWakenPwdLabel = new QLabel(mWakenPwdFrame); mWakenPwdLabel->setFixedSize(550,49);///??????????? mWakenPwdBtn = new KSwitchButton(mWakenPwdFrame); QSize size = mWakenPwdBtn->size(); qDebug() << "mWakenPwdBtn size:" << size; mWakenPwdBtn->setObjectName("lockwaken"); mWakenPwdLayout->addWidget(mWakenPwdLabel); mWakenPwdLayout->addStretch(); mWakenPwdLayout->addWidget(mWakenPwdBtn); PowerLayout->addWidget(mWakenPwdFrame); line_2 = setLine(Powerwidget); PowerLayout->addWidget(line_2); mPowerKeyFrame = new QFrame(Powerwidget); // setFrame_Noframe(mSleepPwdFrame); setFrame_Noframe(mPowerKeyFrame); QHBoxLayout *mPowerKeyLayout = new QHBoxLayout(mPowerKeyFrame); mPowerKeyLayout->setContentsMargins(16, 0, 16, 0); mPowerKeyLabel = new QLabel(mPowerKeyFrame); mPowerKeyLabel->setFixedSize(550,60);//固定了高宽 mPowerKeyComboBox = new QComboBox(mPowerKeyFrame); mPowerKeyComboBox->setObjectName("powerkey");//明天查一下 mPowerKeyComboBox->setMinimumWidth(200); mPowerKeyLayout->addWidget(mPowerKeyLabel); mPowerKeyLayout->addWidget(mPowerKeyComboBox); PowerLayout->addWidget(mPowerKeyFrame); line_3 = setLine(Powerwidget); PowerLayout->addWidget(line_3); mCloseLidFrame = new QFrame(Powerwidget); setFrame_Noframe(mCloseLidFrame); QHBoxLayout *mCloseLidLayout = new QHBoxLayout(mCloseLidFrame); mCloseLidLayout->setContentsMargins(16, 0, 16, 0); mCloseLidLabel = new QLabel(mCloseLidFrame); mCloseLidLabel->setFixedSize(550,59); mCloseLidComboBox = new QComboBox(mCloseLidFrame); mCloseLidComboBox->setObjectName("closelid"); mCloseLidComboBox->setMinimumWidth(200); mCloseLidLayout->addWidget(mCloseLidLabel); mCloseLidLayout->addWidget(mCloseLidComboBox); PowerLayout->addWidget(mCloseLidFrame); mResourceFrame = new QFrame(widget); mResourceFrame->setMinimumSize(QSize(550, 80)); mResourceFrame->setMaximumSize(QSize(16777215, 16777215)); mResourceFrame->setFrameShape(QFrame::Box); QHBoxLayout *mResourceLayout = new QHBoxLayout(mResourceFrame); mResourceLayout->setContentsMargins(16, 0, 16, 0); mResourceLabel = new QLabel(mResourceFrame); mResourceLabel->setAlignment(Qt::AlignBottom); mResourceLabel->setFixedWidth(550); m_resourceDetailLabel = new LightLabel(widget); m_resourceDetailLabel->setText(tr("Reduce the occupation of backend running program resources and ensure smooth operation of key and focus applications.")); m_resourceDetailLabel->setAlignment(Qt::AlignTop); QVBoxLayout *mLabelLayout = new QVBoxLayout(mResourceFrame); mLabelLayout->setSpacing(0); mLabelLayout->setContentsMargins(0,0,0,0); mLabelLayout->addWidget(mResourceLabel); mLabelLayout->addWidget(m_resourceDetailLabel); mResourceSButton = new KSwitchButton(mResourceFrame); mResourceSButton->setFixedSize(49, 24); qDebug() << "mResourceSButton size:" << mResourceSButton->size(); mResourceLayout->addLayout(mLabelLayout); mResourceLayout->addWidget(mResourceSButton); // 添加"显示剩余时间"设置框架 m_remainingTimeFrame = new QFrame(widget); m_remainingTimeFrame->setMinimumSize(QSize(550, 80)); m_remainingTimeFrame->setMaximumSize(QSize(16777215, 16777215)); m_remainingTimeFrame->setFrameShape(QFrame::Box); QHBoxLayout *remainingTimeLayout = new QHBoxLayout(m_remainingTimeFrame); remainingTimeLayout->setContentsMargins(16, 0, 16, 0); m_remainingTimeLabel = new QLabel(m_remainingTimeFrame); m_remainingTimeLabel->setFixedWidth(550); m_remainingTimeSwitch = new KSwitchButton(m_remainingTimeFrame); m_remainingTimeSwitch->setFixedSize(49, 24); remainingTimeLayout->addWidget(m_remainingTimeLabel); remainingTimeLayout->addStretch(); remainingTimeLayout->addWidget(m_remainingTimeSwitch); mverticalLayout->addWidget(Powerwidget); mverticalLayout->addWidget(m_remainingTimeFrame); // 主机灯带设置布局 mHostLightFrame = new QFrame(widget); mHostLightFrame->setMinimumSize(QSize(550, 0)); mHostLightFrame->setMaximumSize(QSize(16777215, 16777215)); mHostLightFrame->setFrameShape(QFrame::Box); QHBoxLayout *mHostLightLayout = new QHBoxLayout(mHostLightFrame); mHostLightLayout->setContentsMargins(16, 0, 16, 0); mHostLightLabel = new QLabel(mHostLightFrame); mHostLightLabel->setFixedSize(550,59); mHostLightSButton = new KSwitchButton(mHostLightFrame); mHostLightLayout->addWidget(mHostLightLabel); mHostLightLayout->addStretch(); mHostLightLayout->addWidget(mHostLightSButton); mverticalLayout->addWidget(mHostLightFrame); mHostLightFrame->setVisible(isSupportHostLight); mverticalLayout->addWidget(mResourceFrame); mverticalLayout->addSpacerItem(new QSpacerItem(20, 24, QSizePolicy::Fixed)); // 使用电源时 mverticalLayout->addWidget(createAcSectionWidget(widget)); mverticalLayout->addSpacerItem(new QSpacerItem(20, 24, QSizePolicy::Fixed)); // 使用电池时 if(mHasBat){ mverticalLayout->addWidget(createBatterySectionWidget(widget)); mverticalLayout->addSpacerItem(new QSpacerItem(20, 24, QSizePolicy::Fixed)); } m_batteryPlanTitleLabel = new KLabel(Powerwidget); m_batteryPlanTitleLabel->setContentsMargins(16, 0, 0, 0); //~ contents_path /Power/Battery saving plan m_batteryPlanTitleLabel->setText((tr("Battery saving plan"))); mverticalLayout->addWidget(m_batteryPlanTitleLabel); // 电池节能计划 Batterywidget = new QFrame(widget); Batterywidget->setMinimumSize(QSize(550, 0)); Batterywidget->setMaximumSize(QSize(16777215, 16777215)); Batterywidget->setFrameShape(QFrame::Box); BatteryLayout = new QVBoxLayout(Batterywidget); BatteryLayout->setContentsMargins(0, 0, 0, 0); BatteryLayout->setSpacing(0); mDarkenFrame = new QFrame(Batterywidget); setFrame_Noframe(mDarkenFrame); QHBoxLayout *mDarkenLayout = new QHBoxLayout(mDarkenFrame); mDarkenLayout->setContentsMargins(16, 0, 16, 0); mDarkenLabel = new QLabel(mDarkenFrame); mDarkenLabel->setFixedSize(550,59); mDarkenComboBox = new QComboBox(mDarkenFrame); mDarkenComboBox->setObjectName("darken"); mDarkenComboBox->setMinimumWidth(200); mDarkenLayout->addWidget(mDarkenLabel); mDarkenLayout->addWidget(mDarkenComboBox); BatteryLayout->addWidget(mDarkenFrame); line_8 = setLine(Batterywidget); BatteryLayout->addWidget(line_8); mLowpowerFrame = new QFrame(Batterywidget); setFrame_Noframe(mLowpowerFrame); mLowpowerLabel1 = new QLabel(mLowpowerFrame); mLowpowerLabel1->setFixedSize(84,60); mLowpowerLabel2 = new QLabel(mLowpowerFrame); mLowpowerLabel2->setFixedSize(370,60); QHBoxLayout *mLowpowerLayout = new QHBoxLayout(mLowpowerFrame); mLowpowerLayout->setContentsMargins(16, 0, 16, 0); m_lowpowerComboBox1 = new QComboBox(mLowpowerFrame); m_lowpowerComboBox1->setObjectName("lowbatterylimit"); m_lowpowerComboBox1->setFixedWidth(80); mLowpowerComboBox2 = new QComboBox(mLowpowerFrame); mLowpowerComboBox2->setObjectName("lowbatterysettings"); mLowpowerComboBox2->setMinimumWidth(200); mLowpowerLayout->setSpacing(8); mLowpowerLayout->addWidget(mLowpowerLabel1); mLowpowerLayout->addWidget(m_lowpowerComboBox1); mLowpowerLayout->addWidget(mLowpowerLabel2); mLowpowerLayout->addWidget(mLowpowerComboBox2); BatteryLayout->addWidget(mLowpowerFrame); line_9 = setLine(Batterywidget); BatteryLayout->addWidget(line_9); mNoticeLFrame = new QFrame(Batterywidget); setFrame_Noframe(mNoticeLFrame); QHBoxLayout *mNoticeLayout = new QHBoxLayout(mNoticeLFrame); mNoticeLayout->setContentsMargins(16, 0, 16, 0); mNoticeLabel = new QLabel(mNoticeLFrame); mNoticeLabel->setFixedSize(550,59); mNoticeComboBox = new QComboBox(mNoticeLFrame); mNoticeComboBox->setObjectName("noticesettings"); mNoticeComboBox->setMinimumWidth(200); mNoticeLayout->addWidget(mNoticeLabel); mNoticeLayout->addWidget(mNoticeComboBox); BatteryLayout->addWidget(mNoticeLFrame); line_10 = setLine(Batterywidget); BatteryLayout->addWidget(line_10); mLowSaveFrame = new QFrame(Batterywidget); setFrame_Noframe(mLowSaveFrame); QHBoxLayout *mLowSaveLayout = new QHBoxLayout(mLowSaveFrame); mLowSaveLayout->setContentsMargins(16, 0, 16, 0); mLowSaveLabel = new QLabel(mLowSaveFrame); mLowSaveLabel->setFixedSize(550,59); mLowSaveBtn = new KSwitchButton(mLowSaveFrame); mLowSaveBtn->setObjectName("lowbatterysave"); mLowSaveLayout->addWidget(mLowSaveLabel); mLowSaveLayout->addStretch(); mLowSaveLayout->addWidget(mLowSaveBtn); BatteryLayout->addWidget(mLowSaveFrame); line_11 = setLine(Batterywidget); BatteryLayout->addWidget(line_11); mBatterySaveFrame = new QFrame(Batterywidget); setFrame_Noframe(mBatterySaveFrame); QHBoxLayout *mBatterySaveLayout = new QHBoxLayout(mBatterySaveFrame); mBatterySaveLayout->setContentsMargins(16, 0, 16, 0); mBatterySaveLabel = new QLabel(mBatterySaveFrame); mBatterySaveLabel->setFixedSize(550,59); mBatterySaveBtn = new KSwitchButton(mBatterySaveFrame); mBatterySaveBtn->setObjectName("batterysave"); mBatterySaveLayout->addWidget(mBatterySaveLabel); mBatterySaveLayout->addStretch(); mBatterySaveLayout->addWidget(mBatterySaveBtn); BatteryLayout->addWidget(mBatterySaveFrame); line_12 = setLine(Batterywidget); BatteryLayout->addWidget(line_12); mDisplayTimeFrame = new QFrame(Batterywidget); setFrame_Noframe(mDisplayTimeFrame); QHBoxLayout *mDisplayTimeLayout = new QHBoxLayout(mDisplayTimeFrame); mDisplayTimeLayout->setContentsMargins(16, 0, 16, 0); mDisplayTimeLabel = new QLabel(mDisplayTimeFrame); mDisplayTimeLabel->setFixedSize(550,59); mDisplayTimeBtn = new KSwitchButton(mDisplayTimeFrame); mDisplayTimeBtn->setObjectName("powershowtime"); mDisplayTimeLayout->addWidget(mDisplayTimeLabel); mDisplayTimeLayout->addStretch(); mDisplayTimeLayout->addWidget(mDisplayTimeBtn); BatteryLayout->addWidget(mDisplayTimeFrame); mverticalLayout->addWidget(Batterywidget); mverticalLayout->addStretch(); retranslateUi(); } void Power::setVisibleBySecurity() { // 安全管控 免密登录及自动登录设置项的显示与隐藏 QVariantMap ModuleMap = UkccCommon::getModuleHideStatus(); QString moduleSettings = ModuleMap.value(name().toLower() + "Settings").toString(); qDebug()<setVisible(item.at(1) == "true"); m_acCloseDisplayLine->setVisible(item.at(1) == "true"); } if (item.at(0) == "SleepFrame") { m_acSleepFrame->setVisible(item.at(1) == "true"); } if (item.at(0) == "mSleepPwdFrame") { mSleepPwdFrame->setVisible(item.at(1) == "true"); line_1->setVisible(item.at(1) == "true"); } if (item.at(0) == "mWakenPwdFrame") { mWakenPwdFrame->setVisible(item.at(1) == "true"); line_2->setVisible(item.at(1) == "true"); } } if (UkccCommon::getCpuInfo().contains("9006C", Qt::CaseInsensitive)) { mResourceFrame->setVisible(false); } } bool Power::kconf2Enable(const QString &cloudPlatForm) const { if (cloudPlatForm == "huawei") { qDebug() << Q_FUNC_INFO << m_isExistHibernate << m_isExistHibernate; if ((!m_isExistHibernate) && (!m_isExistSuspend)) return false; } return true; } void Power::initInterface() { if (mHibernateInterface == nullptr) { mHibernateInterface = new QDBusInterface("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", QDBusConnection::systemBus(),this); isSuspendSupply(); isHibernateSupply(); isSuspend2HibernateSupply(); } } bool Power::isSuspend2HibernateSupply() { if (!mHibernateInterface || !mHibernateInterface->isValid()) { qWarning() << "login1 interface invalid for CanSuspendThenHibernate"; m_isExistS2H = false; return m_isExistS2H; } QDBusReply reply = mHibernateInterface->call("CanSuspend2Hibernate"); if (!reply.isValid()) { qWarning() << "CanSuspend2Hibernate call failed:" << QDBusConnection::systemBus().lastError(); m_isExistS2H = false; return m_isExistS2H; } const QString v = reply.value(); m_isExistS2H = (v == "yes"); return m_isExistS2H; } void Power::retranslateUi() { //~ contents_path /Power/Require password when suspend/hibernate QString str = (m_isExistHibernate && m_isExistSuspend) ? tr("Require password when suspend/hibernate") : (m_isExistSuspend ? tr("Require password when suspend") : (m_isExistHibernate ? tr("Require password when hibernate") : "")); if (str.isEmpty()) { mSleepPwdFrame->setVisible(false); } if (QLabelSetText(mSleepPwdLabel, str)) { mSleepPwdLabel->setToolTip(str); } //~ contents_path /Power/Password required when waking up the screen if (QLabelSetText(mWakenPwdLabel, tr("Password required when waking up the screen"))) { mSleepPwdLabel->setToolTip(tr("Password required when waking up the screen")); } //~ contents_path /Power/Press the power button if (QLabelSetText(mPowerKeyLabel, tr("Press the power button"))) { mPowerKeyLabel->setToolTip("Press the power button"); } //~ contents_path /Power/Time to close display if (QLabelSetText(m_acCloseDisplayLabel, tr("Time to close display"))) { m_acCloseDisplayLabel->setToolTip(tr("Time to close display")); } if(mHasBat) { //~ contents_path /Power/Time to close display if (QLabelSetText(m_batteryCloseDisplayLabel, tr("Time to close display"))) { m_batteryCloseDisplayLabel->setToolTip(tr("Time to close display")); } //~ contents_path /Power/Time to sleep if (QLabelSetText(m_batterySleepLabel, tr("Time to sleep"))) { m_batterySleepLabel->setToolTip(tr("Time to sleep")); } //~ contents_path /Power/Using battery if (QLabelSetText(m_batteryPowerLabel, tr("Power plan"))) { m_batteryPowerLabel->setToolTip(tr("Power plan")); } //~ contents_path /Power/Time to hibernate if (QLabelSetText(m_batteryHibernateLabel, tr("After this period, the system will transition from sleep to hibernation."))) { m_batteryHibernateLabel->setToolTip(tr("After this period, the system will transition from sleep to hibernation.")); } } //~ contents_path /Power/Time to sleep if (QLabelSetText(m_acSleepLabel, tr("Time to sleep"))) { m_acSleepLabel->setToolTip(tr("Time to sleep")); } //~ contents_path /Power/Time to hibernate if (QLabelSetText(m_acHibernateLabel, tr("After this period, the system will transition from sleep to hibernation."))) { m_acHibernateLabel->setToolTip(tr("After this period, the system will transition from sleep to hibernation.")); } //~ contents_path /Power/Notebook cover if (QLabelSetText(mCloseLidLabel, tr("Notebook cover"))) { mCloseLidLabel->setToolTip(tr("Notebook cover")); } //~ contents_path /Power/Host light strip if (QLabelSetText(mHostLightLabel, tr("Host light strip"))) { mHostLightLabel->setToolTip(tr("Host light strip")); } //~ contents_path /Power/Dynamic resource scheduling if (QLabelSetText(mResourceLabel, tr("Dynamic resource scheduling"))) { mResourceLabel->setToolTip(tr("Dynamic resource scheduling")); } if (QLabelSetText(m_remainingTimeLabel, tr("Display remaining charging and discharging time"))) { m_remainingTimeLabel->setToolTip(tr("Display remaining charging and discharging time")); } //~ contents_path /Power/Using power if (QLabelSetText(m_acPowerLabel, tr("Power plan"))) { m_acPowerLabel->setToolTip(tr("Power plan")); } if (QLabelSetText(mDarkenLabel, tr(" Time to darken"))) { mDarkenLabel->setToolTip(tr(" Time to darken")); } if (QLabelSetText(mLowpowerLabel1, tr("Battery level is lower than"))) { mLowpowerLabel1->setToolTip(tr("Battery level is lower than")); } mLowpowerLabel2->setText(tr("Run")); //~ contents_path /Power/Low battery notification if (QLabelSetText(mNoticeLabel, tr("Low battery notification"))) { mNoticeLabel->setToolTip(tr("Low battery notification")); } //~ contents_path /Power/"Automatically run saving mode when low battery if (QLabelSetText(mLowSaveLabel, tr("Automatically run saving mode when low battery"))) { mLowSaveLabel->setToolTip(tr("Automatically run saving mode when the low battery")); } if (QLabelSetText(mBatterySaveLabel, tr("Automatically run saving mode when using battery"))) { mBatterySaveLabel->setToolTip(tr("Automatically run saving mode when using battery")); } if (QLabelSetText(mDisplayTimeLabel, tr("Display remaining charging time and usage time"))) { mDisplayTimeLabel->setToolTip(tr("Display remaining charging time and usage time")); } } void Power::resetui() { mBatterySaveFrame->hide(); mDarkenFrame->hide(); mDisplayTimeFrame->hide(); line_8->hide(); line_11->hide(); line_12->hide(); //不存在盖子隐藏该项 if (!mIsExistLid) { mCloseLidFrame->hide(); } // 不存在电池隐藏这些设置项 if (!mHasBat) { m_batteryPlanTitleLabel->hide(); clearAutoItem(BatteryLayout); Batterywidget->hide(); } //Intel作如下处理 if (UkccCommon::isTablet()) { mSleepPwdFrame->hide(); mWakenPwdFrame->hide(); mPowerKeyFrame->hide(); mCloseLidFrame->hide(); mDarkenFrame->hide(); mLowpowerFrame->hide(); mNoticeLFrame->hide(); mDisplayTimeFrame->hide(); mItem->changeSize(0, 0); line_1->hide(); line_2->hide(); line_3->hide(); line_8->hide(); line_9->hide(); line_10->hide(); line_11->hide(); line_12->hide(); } } void Power::setupComponent() { // 合盖 closeLidStringList << tr("Nothing") << tr("Blank") << tr("Shutdown") << tr("Suspend") << tr("Hibernate"); mCloseLidComboBox->insertItem(0, closeLidStringList.at(0), "nothing"); mCloseLidComboBox->insertItem(1, closeLidStringList.at(1), "blank"); mCloseLidComboBox->insertItem(2, closeLidStringList.at(2), "shutdown"); if (m_isExistSuspend) mCloseLidComboBox->insertItem(3, closeLidStringList.at(3), "suspend"); if (m_isExistHibernate) { mCloseLidComboBox->insertItem(4, closeLidStringList.at(4), "hibernate"); } //按下电源键时 buttonStringList << tr("Interactive") << tr("Shutdown") << tr("Suspend") << tr("Hibernate"); mPowerKeyComboBox->insertItem(0, buttonStringList.at(0), "interactive"); mPowerKeyComboBox->insertItem(1, buttonStringList.at(1), "shutdown"); if (m_isExistSuspend) mPowerKeyComboBox->insertItem(2, buttonStringList.at(2), "suspend"); if (m_isExistHibernate) mPowerKeyComboBox->insertItem(3, buttonStringList.at(3), "hibernate"); //关闭显示器 closeStringList <insertItem(0, closeStringList.at(0), QVariant::fromValue(1)); m_acCloseDisplayComboBox->insertItem(1, closeStringList.at(1), QVariant::fromValue(5)); m_acCloseDisplayComboBox->insertItem(2, closeStringList.at(2), QVariant::fromValue(10)); m_acCloseDisplayComboBox->insertItem(3, closeStringList.at(3), QVariant::fromValue(15)); m_acCloseDisplayComboBox->insertItem(4, closeStringList.at(4), QVariant::fromValue(30)); m_acCloseDisplayComboBox->insertItem(5, closeStringList.at(5), QVariant::fromValue(60)); m_acCloseDisplayComboBox->insertItem(6, closeStringList.at(6), QVariant::fromValue(120)); m_acCloseDisplayComboBox->insertItem(7, closeStringList.at(7), QVariant::fromValue(0)); if(mHasBat){ //关闭显示器 closeStringList_battery <insertItem(0, closeStringList.at(0), QVariant::fromValue(1)); m_batteryCloseDisplayComboBox->insertItem(1, closeStringList.at(1), QVariant::fromValue(5)); m_batteryCloseDisplayComboBox->insertItem(2, closeStringList.at(2), QVariant::fromValue(10)); m_batteryCloseDisplayComboBox->insertItem(3, closeStringList.at(3), QVariant::fromValue(15)); m_batteryCloseDisplayComboBox->insertItem(4, closeStringList.at(4), QVariant::fromValue(30)); m_batteryCloseDisplayComboBox->insertItem(5, closeStringList.at(5), QVariant::fromValue(60)); m_batteryCloseDisplayComboBox->insertItem(6, closeStringList.at(6), QVariant::fromValue(120)); m_batteryCloseDisplayComboBox->insertItem(7, closeStringList.at(7), QVariant::fromValue(0)); } //睡眠 sleepStringList << tr("10min") << tr("15min") << tr("30min") << tr("1h") << tr("2h") << tr("3h") << tr("Never"); m_acSleepComboBox->insertItem(0, sleepStringList.at(0), QVariant::fromValue(10)); m_acSleepComboBox->insertItem(1, sleepStringList.at(1), QVariant::fromValue(15)); m_acSleepComboBox->insertItem(2, sleepStringList.at(2), QVariant::fromValue(30)); m_acSleepComboBox->insertItem(3, sleepStringList.at(3), QVariant::fromValue(60)); m_acSleepComboBox->insertItem(4, sleepStringList.at(4), QVariant::fromValue(120)); m_acSleepComboBox->insertItem(5, sleepStringList.at(5), QVariant::fromValue(180)); m_acSleepComboBox->insertItem(6, sleepStringList.at(6), QVariant::fromValue(0)); //休眠 acHibernateStringList << tr("30min") << tr("1h") << tr("2h") << tr("3h") << tr("4h") << tr("5h")<< tr("Never"); m_acHibernateComboBox->insertItem(0, acHibernateStringList.at(0), QVariant::fromValue(30)); m_acHibernateComboBox->insertItem(1, acHibernateStringList.at(1), QVariant::fromValue(60)); m_acHibernateComboBox->insertItem(2, acHibernateStringList.at(2), QVariant::fromValue(120)); m_acHibernateComboBox->insertItem(3, acHibernateStringList.at(3), QVariant::fromValue(180)); m_acHibernateComboBox->insertItem(4, acHibernateStringList.at(4), QVariant::fromValue(240)); m_acHibernateComboBox->insertItem(5, acHibernateStringList.at(5), QVariant::fromValue(300)); m_acHibernateComboBox->insertItem(6, acHibernateStringList.at(6), QVariant::fromValue(0)); if (mHasBat) { //睡眠 sleepStringList_battery << tr("10min") << tr("15min") << tr("30min") << tr("1h") << tr("2h") << tr("3h") << tr("Never"); m_batterySleepComboBox->insertItem(0, sleepStringList.at(0), QVariant::fromValue(10)); m_batterySleepComboBox->insertItem(1, sleepStringList.at(1), QVariant::fromValue(15)); m_batterySleepComboBox->insertItem(2, sleepStringList.at(2), QVariant::fromValue(30)); m_batterySleepComboBox->insertItem(3, sleepStringList.at(3), QVariant::fromValue(60)); m_batterySleepComboBox->insertItem(4, sleepStringList.at(4), QVariant::fromValue(120)); m_batterySleepComboBox->insertItem(5, sleepStringList.at(5), QVariant::fromValue(180)); m_batterySleepComboBox->insertItem(6, sleepStringList.at(6), QVariant::fromValue(0)); //休眠 batteryHibernateStringList << tr("30min") << tr("1h") << tr("2h") << tr("3h") << tr("4h") << tr("5h")<< tr("Never"); m_batteryHibernateComboBox->insertItem(0, batteryHibernateStringList.at(0), QVariant::fromValue(30)); m_batteryHibernateComboBox->insertItem(1, batteryHibernateStringList.at(1), QVariant::fromValue(60)); m_batteryHibernateComboBox->insertItem(2, batteryHibernateStringList.at(2), QVariant::fromValue(120)); m_batteryHibernateComboBox->insertItem(3, batteryHibernateStringList.at(3), QVariant::fromValue(180)); m_batteryHibernateComboBox->insertItem(4, batteryHibernateStringList.at(4), QVariant::fromValue(240)); m_batteryHibernateComboBox->insertItem(5, batteryHibernateStringList.at(5), QVariant::fromValue(300)); m_batteryHibernateComboBox->insertItem(6, batteryHibernateStringList.at(6), QVariant::fromValue(0)); } //电源计划 PowerplanStringList << tr("Balance") << tr("Energy Efficiency")<insertItem(0, PowerplanStringList.at(0), "Balance"); m_acPowerComboBox->insertItem(1, PowerplanStringList.at(1), "Energy Efficiency"); m_acPowerComboBox->insertItem(2, PowerplanStringList.at(2), "Performance"); if (mHasBat) { BatteryplanStringList << tr("Balance") << tr("Energy Efficiency")<insertItem(0, BatteryplanStringList.at(0), "Balance"); m_batteryPowerComboBox->insertItem(1, BatteryplanStringList.at(1), "Energy Efficiency"); m_batteryPowerComboBox->insertItem(2, BatteryplanStringList.at(2), "Performance"); } //低电量时执行 LowpowerStringList << tr("Nothing") << tr("Blank") << tr("Shutdown") << tr("Suspend") << tr("Hibernate"); mLowpowerComboBox2->insertItem(0, LowpowerStringList.at(0), "nothing"); mLowpowerComboBox2->insertItem(1, LowpowerStringList.at(1), "blank"); mLowpowerComboBox2->insertItem(2, LowpowerStringList.at(2), "shutdown"); if (m_isExistSuspend) mLowpowerComboBox2->insertItem(3, LowpowerStringList.at(3), "suspend"); if (m_isExistHibernate) mLowpowerComboBox2->insertItem(4, LowpowerStringList.at(4), "hibernate"); //低电量通知 for (int i = 1; i < 5; i++) { mNoticeComboBox->insertItem(i-1, QString("%1%").arg(i*10)); } //电池低电量范围 int batteryRemain = settings->get(PER_ACTION_CRI).toInt(); for(int i = 0; i < batteryRemain; i++) { m_lowpowerComboBox1->insertItem(i, QString("%1%").arg(i+1)); } } void Power::setupConnect() { connect(mSleepPwdBtn,&KSwitchButton::stateChanged, [=](bool checked){ UkccCommon::buriedSettings(name(), "whether password is required for wake-up after sleep", QString("settings"), checked ? "true" : "false"); screensettings->set(SLEEP_ACTIVATION_ENABLED,checked); }); if (screensettings->keys().contains("closeActivationEnabled")) { connect(mWakenPwdBtn,&KSwitchButton::stateChanged, [=](bool checked){ UkccCommon::buriedSettings(name(), "whether password is required for wake-up screen", QString("settings"), checked ? "true" : "false"); screensettings->set(CLOSE_ACTIVATION_ENABLED,checked); }); } // 连接剩余时间显示开关信号 connect(m_remainingTimeSwitch, &KSwitchButton::stateChanged, this, [=](bool checked) { UkccCommon::buriedSettings(name(), "Display remaining time", QString("settings"), checked ? "true" : "false"); settings->set(DISPLAY_LEFT_TIME_OF_CHARGE_AND_DISCHARGE, checked); qDebug() << "Display remaining time feature is now" << (checked ? "enabled" : "disabled"); }); connect(mPowerKeyComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { UkccCommon::buriedSettings(name(), "execute when pressing the power key", QString("select"), mPowerKeyComboBox->itemData(index).toString()); settings->set(BUTTON_POWER_KEY, mPowerKeyComboBox->itemData(index)); }); connect(m_acCloseDisplayComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { Q_UNUSED(index) UkccCommon::buriedSettings(name(), "turn off the display after this time period", QString("select"), m_acCloseDisplayComboBox->currentData().toString()); if (m_acCloseDisplayComboBox->currentData(Qt::UserRole).toInt() == 0) { settings->set(SLEEP_DISPLAY_AC_KEY, -1); qDebug()<<"sleep-display-ac : "<trySet(SLEEP_DISPLAY_AC_KEY, -1); } else { settings->set(SLEEP_DISPLAY_AC_KEY, QVariant(m_acCloseDisplayComboBox->currentData(Qt::UserRole).toInt() * 60)); qDebug()<<"sleep-display-ac : "<trySet(SLEEP_DISPLAY_AC_KEY, m_acCloseDisplayComboBox->currentData(Qt::UserRole).toInt() * 60); } setHintLable(); }); if(mHasBat) { connect(m_batteryCloseDisplayComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { Q_UNUSED(index) if (m_batteryCloseDisplayComboBox->currentData(Qt::UserRole).toInt() == 0) { settings->set(SLEEP_DISPLAY_BATT_KEY, -1); qDebug()<<"sleep-display-battery : "<trySet(SLEEP_DISPLAY_BATT_KEY, -1); } else { settings->set(SLEEP_DISPLAY_BATT_KEY, QVariant(m_batteryCloseDisplayComboBox->currentData(Qt::UserRole).toInt() * 60)); qDebug()<<"sleep-display-battery : "<trySet(SLEEP_DISPLAY_BATT_KEY, m_batteryCloseDisplayComboBox->currentData(Qt::UserRole).toInt() * 60); } setHintLable(); }); connect(m_batterySleepComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { Q_UNUSED(index) if (m_batterySleepComboBox->currentData(Qt::UserRole).toInt() == 0) { settings->set(SLEEP_COMPUTER_BATT_KEY, -1); qDebug()<<"sleep-computer-battery : "<trySet(SLEEP_COMPUTER_BATT_KEY, -1); } else { settings->set(SLEEP_COMPUTER_BATT_KEY, QVariant(m_batterySleepComboBox->currentData(Qt::UserRole).toInt() * 60)); qDebug()<<"sleep-computer-battery : "<trySet(SLEEP_COMPUTER_BATT_KEY, m_batterySleepComboBox->currentData(Qt::UserRole).toInt() * 60); } setHintLable(); }); connect(m_batteryHibernateComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this]() { int value = m_batteryHibernateComboBox->currentData(Qt::UserRole).toInt(); int seconds = (value == 0) ? -1 : value * 60; qDebug()<<"hibernate-computer-battery : " << settings->trySet(HIBERNATE_COMPUTER_BATT_KEY, seconds); }); } connect(m_acSleepComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { Q_UNUSED(index) UkccCommon::buriedSettings(name(), "the system go to sleep after this time period", QString("select"), m_acSleepComboBox->currentData().toString()); if (m_acSleepComboBox->currentData(Qt::UserRole).toInt() == 0) { settings->set(SLEEP_COMPUTER_AC_KEY, -1); qDebug()<<"sleep-computer-ac : "<trySet(SLEEP_COMPUTER_AC_KEY, -1); } else { settings->set(SLEEP_COMPUTER_AC_KEY, QVariant(m_acSleepComboBox->currentData(Qt::UserRole).toInt() * 60)); qDebug()<<"sleep-computer-ac : "<trySet(SLEEP_COMPUTER_AC_KEY, m_acSleepComboBox->currentData(Qt::UserRole).toInt() * 60); } setHintLable(); }); connect(m_acHibernateComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this]() { int value = m_acHibernateComboBox->currentData(Qt::UserRole).toInt(); int seconds = (value == 0) ? -1 : value * 60; qDebug()<<"hibernate-computer-ac : " << settings->trySet(HIBERNATE_COMPUTER_AC_KEY, seconds); }); connect(mCloseLidComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { UkccCommon::buriedSettings(name(), "execute when the notebook is closed", QString("select"), mCloseLidComboBox->currentData().toString()); settings->set(BUTTON_LID_AC_KEY, mCloseLidComboBox->itemData(index)); settings->set(BUTTON_LID_BATT_KET, mCloseLidComboBox->itemData(index)); }); connect(mHostLightSButton, &KSwitchButton::stateChanged, this, [=](bool checked){ UkccCommon::buriedSettings(name(), "Host light strip", QString("settings"), checked ? "true":"false"); QDBusReply ret = hostLightStripDbus->call("setHostLightStrip", checked); if (!ret) { qDebug() << "setHostLightStrip failed!"; mHostLightSButton->blockSignals(true); mHostLightSButton->setChecked(!checked); mHostLightSButton->blockSignals(false); } }); connect(mResourceSButton, &KSwitchButton::clicked, this, [=](bool checked){ if (mProcManagerSettings != nullptr && mProcManagerSettings->keys().contains("resourceLimitEnabled")) { mProcManagerSettings->set(RESOURCE_LIMIT_ENABLED, checked); } }); if (mKeys.contains("powerPolicyAc") && mKeys.contains("powerPolicyBattery")) { connect(m_acPowerComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { UkccCommon::buriedSettings(name(), "mode when using power supply", QString("select"), m_acPowerComboBox->currentData().toString()); if (index == 0) { settings->set(POWER_POLICY_AC, 1); } else if (index == 1) { settings->set(POWER_POLICY_AC, 2); } else { settings->set(POWER_POLICY_AC, 0); } }); if(mHasBat) { connect(m_batteryPowerComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { UkccCommon::buriedSettings(name(), "mode when using battery supply", QString("select"), m_batteryPowerComboBox->currentData().toString()); if (index == 0) { settings->set(POWER_POLICY_BATTARY, 1); } else if (index == 1) { settings->set(POWER_POLICY_BATTARY, 2); } else { settings->set(POWER_POLICY_BATTARY, 0); } }); } } connect(mDarkenComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { Q_UNUSED(index) UkccCommon::buriedSettings(name(), "reduce screen brightness after this time period", QString("select"), m_batteryPowerComboBox->currentData().toString()); if (mDarkenComboBox->currentData(Qt::UserRole).toInt() == 0) { settings->set(IDLE_DIM_TIME_KEY, -1); } else { settings->set(IDLE_DIM_TIME_KEY, QVariant(mDarkenComboBox->currentData(Qt::UserRole).toInt() * 60)); } }); connect(m_lowpowerComboBox1, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { UkccCommon::buriedSettings(name(), "low battery value", QString("select"), m_lowpowerComboBox1->currentData().toString()); settings->set(PER_ACTION_KEY, index + 1); }); connect(mLowpowerComboBox2, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { UkccCommon::buriedSettings(name(), "execute below low battery level", QString("select"), mLowpowerComboBox2->currentData().toString()); settings->set(ACTION_CRI_BTY, mLowpowerComboBox2->itemData(index)); }); connect(mNoticeComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { UkccCommon::buriedSettings(name(), "notify when the power is lower than this value", QString("select"), mNoticeComboBox->currentText()); settings->set(PERCENTAGE_LOW, (index + 1)*10); }); connect(mLowSaveBtn,&KSwitchButton::stateChanged, [=](bool checked){ UkccCommon::buriedSettings(name(), "whether the saving mode is autoturned on when the battery is low", QString("select"), checked ? "true" : "false"); settings->set(LOW_BATTERY_AUTO_SAVE,checked); }); connect(settings, &QGSettings::changed, this, &Power::initCustomPlanStatus); connect(screensettings,&QGSettings::changed,[=](){ initCustomPlanStatus(); }); if (mProcManagerSettings != nullptr && mProcManagerSettings->keys().contains("resourceLimitEnabled")) { connect(mProcManagerSettings, &QGSettings::changed, this, &Power::initCustomPlanStatus); } setVisibleBySecurity(); QDBusConnection::sessionBus().connect(QString(), QString("/"), "org.ukui.ukcc.session.interface", "configChanged", this, SLOT(setVisibleBySecurity())); setEnableBySecurity(); QDBusConnection::sessionBus().connect(QString(), QString("/"), "org.ukui.ukcc.session.interface", "configChanged", this, SLOT(setEnableBySecurity())); } void Power::initCustomPlanStatus() { // 信号阻塞 mPowerKeyComboBox->blockSignals(true); m_acCloseDisplayComboBox->blockSignals(true); m_acSleepComboBox->blockSignals(true); m_acHibernateComboBox->blockSignals(true); mCloseLidComboBox->blockSignals(true); m_acPowerComboBox->blockSignals(true); if (mHasBat) { m_batteryPowerComboBox->blockSignals(true); m_batteryHibernateComboBox->blockSignals(true); } m_lowpowerComboBox1->blockSignals(true); mLowpowerComboBox2->blockSignals(true); mNoticeComboBox->blockSignals(true); mSleepPwdBtn->blockSignals(true); mWakenPwdBtn->blockSignals(true); mLowSaveBtn->blockSignals(true); mBatterySaveBtn->blockSignals(true); mPowerKeyComboBox->setCurrentIndex(mPowerKeyComboBox->findData(settings->get(BUTTON_POWER_KEY).toString())); if (settings->get(SLEEP_COMPUTER_AC_KEY).toInt() == -1) { m_acSleepComboBox->setCurrentIndex(m_acSleepComboBox->findData(0)); } else { m_acSleepComboBox->setCurrentIndex(m_acSleepComboBox->findData(settings->get(SLEEP_COMPUTER_AC_KEY).toInt() / FIXES)); } if (settings->get(SLEEP_DISPLAY_AC_KEY).toInt() == -1) { m_acCloseDisplayComboBox->setCurrentIndex(m_acCloseDisplayComboBox->findData(0)); } else { m_acCloseDisplayComboBox->setCurrentIndex(m_acCloseDisplayComboBox->findData(settings->get(SLEEP_DISPLAY_AC_KEY).toInt() / FIXES));; } if (settings->get(HIBERNATE_COMPUTER_AC_KEY).toInt() == -1) { m_acHibernateComboBox->setCurrentIndex(m_acHibernateComboBox->findData(0)); } else { m_acHibernateComboBox->setCurrentIndex(m_acHibernateComboBox->findData(settings->get(HIBERNATE_COMPUTER_AC_KEY).toInt() / FIXES)); } if(mHasBat) { if (settings->get(SLEEP_COMPUTER_BATT_KEY).toInt() == -1) { m_batterySleepComboBox->setCurrentIndex(m_batterySleepComboBox->findData(0)); } else { m_batterySleepComboBox->setCurrentIndex(m_batterySleepComboBox->findData(settings->get(SLEEP_COMPUTER_BATT_KEY).toInt() / FIXES)); } if (settings->get(SLEEP_DISPLAY_BATT_KEY).toInt() == -1) { m_batteryCloseDisplayComboBox->setCurrentIndex(m_batteryCloseDisplayComboBox->findData(0)); } else { m_batteryCloseDisplayComboBox->setCurrentIndex(m_batteryCloseDisplayComboBox->findData(settings->get(SLEEP_DISPLAY_BATT_KEY).toInt() / FIXES)); } if (settings->get(HIBERNATE_COMPUTER_BATT_KEY).toInt() == -1) { m_batteryHibernateComboBox->setCurrentIndex(m_batteryHibernateComboBox->findData(0)); } else { m_batteryHibernateComboBox->setCurrentIndex(m_batteryHibernateComboBox->findData(settings->get(HIBERNATE_COMPUTER_BATT_KEY).toInt() / FIXES)); } } setHintLable(); mCloseLidComboBox->setCurrentIndex(mCloseLidComboBox->findData(settings->get(BUTTON_LID_AC_KEY).toString())); if (isSupportHostLight && hostLightStripDbus != nullptr) { mHostLightSButton->blockSignals(true); QDBusReply ret = hostLightStripDbus->call("getHostLightStripStatus"); mHostLightSButton->setChecked(ret); mHostLightSButton->blockSignals(false); } if (mProcManagerSettings != nullptr && mProcManagerSettings->keys().contains("resourceLimitEnabled")) { mResourceSButton->blockSignals(true); mResourceSButton->setChecked(mProcManagerSettings->get(RESOURCE_LIMIT_ENABLED).toBool()); mResourceSButton->blockSignals(false); } if (settings->keys().contains(DISPLAY_LEFT_TIME_OF_CHARGE_AND_DISCHARGE)) { m_remainingTimeSwitch->blockSignals(true); m_remainingTimeSwitch->setChecked(settings->get(DISPLAY_LEFT_TIME_OF_CHARGE_AND_DISCHARGE).toBool()); m_remainingTimeSwitch->blockSignals(false); } if (mKeys.contains("powerPolicyAc") && mKeys.contains("powerPolicyBattery")) { if (1 == settings->get(POWER_POLICY_AC).toInt()) { m_acPowerComboBox->setCurrentIndex(0); } else if (2 == settings->get(POWER_POLICY_AC).toInt()){ m_acPowerComboBox->setCurrentIndex(1); } else { m_acPowerComboBox->setCurrentIndex(2); } if(mHasBat) { if (1 == settings->get(POWER_POLICY_BATTARY).toInt()) { m_batteryPowerComboBox->setCurrentIndex(0); } else if (2 == settings->get(POWER_POLICY_BATTARY).toInt()) { m_batteryPowerComboBox->setCurrentIndex(1); } else { m_batteryPowerComboBox->setCurrentIndex(2); } } } else { m_acPowerComboBox->setEnabled(false); if( mHasBat){ m_batteryPowerComboBox->setEnabled(false); } } m_lowpowerComboBox1->setCurrentIndex(settings->get(PER_ACTION_KEY).toInt() - 1); mLowpowerComboBox2->setCurrentIndex(mLowpowerComboBox2->findData(settings->get(ACTION_CRI_BTY).toString())); mNoticeComboBox->setCurrentIndex(settings->get(PERCENTAGE_LOW).toInt()/10 - 1); if (screensettings->keys().contains("sleepActivationEnabled")) { mSleepPwdBtn->setChecked(screensettings->get(SLEEP_ACTIVATION_ENABLED).toBool()); } if (screensettings->keys().contains("closeActivationEnabled")) mWakenPwdBtn->setChecked(screensettings->get(CLOSE_ACTIVATION_ENABLED).toBool()); if (mKeys.contains("lowBatteryAutoSave")) { mLowSaveBtn->setChecked(settings->get(LOW_BATTERY_AUTO_SAVE).toBool()); } else { mLowSaveFrame->hide(); line_10->hide(); } // 信号阻塞解除 mPowerKeyComboBox->blockSignals(false); m_acCloseDisplayComboBox->blockSignals(false); m_acSleepComboBox->blockSignals(false); m_acHibernateComboBox->blockSignals(false); mCloseLidComboBox->blockSignals(false); m_acPowerComboBox->blockSignals(false); if (mHasBat) { m_batteryPowerComboBox->blockSignals(false); m_batteryHibernateComboBox->blockSignals(false); } m_lowpowerComboBox1->blockSignals(false); mLowpowerComboBox2->blockSignals(false); mNoticeComboBox->blockSignals(false); mSleepPwdBtn->blockSignals(false); mWakenPwdBtn->blockSignals(false); mLowSaveBtn->blockSignals(false); mBatterySaveBtn->blockSignals(false); } void Power::isLidPresent() { QDBusInterface *LidInterface = new QDBusInterface("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.DBus.Properties", QDBusConnection::systemBus(),this); if (!LidInterface->isValid()) { qDebug() << "Create UPower Lid Interface Failed : " << QDBusConnection::systemBus().lastError(); return; } QDBusReply LidInfo; LidInfo = LidInterface->call("Get", "org.freedesktop.UPower", "LidIsPresent"); mIsExistLid = LidInfo.value().toBool(); } bool Power::isHibernateSupply() { if (!mHibernateInterface->isValid()) { qDebug() << "Create login1 Hibernate Interface Failed : " << QDBusConnection::systemBus().lastError(); return false; } QDBusReply HibernateInfo; HibernateInfo = mHibernateInterface->call("CanHibernate"); m_isExistHibernate = HibernateInfo == "yes" ? true : false; return m_isExistHibernate; } // 是否支持睡眠 bool Power::isSuspendSupply() { if (!mHibernateInterface->isValid()) { qDebug() << "Create login1 CanSuspend Interface Failed : " << QDBusConnection::systemBus().lastError(); return false; } QDBusReply HibernateInfo; HibernateInfo = mHibernateInterface->call("CanSuspend"); if (HibernateInfo == "yes" || HibernateInfo == "challenge") { // bug#200148 m_isExistSuspend = true; } else { m_isExistSuspend = false; } return m_isExistSuspend; } bool Power::isExitBattery() { /* 默认机器没有电池 */ mHasBat = false; QDBusInterface *brightnessInterface = new QDBusInterface("org.freedesktop.UPower", "/org/freedesktop/UPower/devices/DisplayDevice", "org.freedesktop.DBus.Properties", QDBusConnection::systemBus(), this); if (!brightnessInterface->isValid()) { qDebug() << "Create UPower Interface Failed : " << QDBusConnection::systemBus().lastError(); return false; } QDBusReply briginfo; briginfo = brightnessInterface ->call("Get", "org.freedesktop.UPower.Device", "PowerSupply"); if (briginfo.value().toBool()) { mHasBat = true ; } return mHasBat; } bool Power::QLabelSetText(QLabel *label, QString string) { bool is_over_length = false; QFontMetrics fontMetrics(label->font()); // Qt6: width() 已被移除,使用 horizontalAdvance() 替代 int fontSize = fontMetrics.horizontalAdvance(string); QString str = string; if (fontSize > (label->width()-5)) { str = fontMetrics.elidedText(string, Qt::ElideRight, label->width()); is_over_length = true; } label->setText(str); return is_over_length; } void Power::clearAutoItem(QVBoxLayout *mLyt) { if (mLyt->layout() != NULL) { QLayoutItem *item; while ((item = mLyt->layout()->takeAt(0)) != NULL) { if(item->widget()) { item->widget()->setParent(NULL); } delete item; item = nullptr; } } } void Power::setFrame_Noframe(QFrame *frame) { frame->setMinimumSize(QSize(550, 60)); frame->setFrameShape(QFrame::NoFrame); } QFrame *Power::setLine(QFrame *frame) { QFrame *line = new QFrame(frame); line->setMinimumSize(QSize(0, 1)); line->setMaximumSize(QSize(16777215, 1)); line->setLineWidth(0); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); return line; } void Power::setHintLable() { if ((((m_acCloseDisplayComboBox->currentData().toInt() > m_acSleepComboBox->currentData().toInt()) && m_acSleepComboBox->currentData().toInt() !=0) || (m_acCloseDisplayComboBox->currentData().toInt() == 0 && m_acSleepComboBox->currentData().toInt() != 0)) && m_isExistSuspend) { m_acCloseDisplayHintIcon->setVisible(true); m_acCloseDisplayHintLabel->setVisible(true); m_acCloseDisplayFrame->setMinimumHeight(100); } else { m_acCloseDisplayHintIcon->setVisible(false); m_acCloseDisplayHintLabel->setVisible(false); m_acCloseDisplayFrame->setMinimumHeight(60); } // 电池区块 if (m_batteryCloseDisplayComboBox && m_batterySleepComboBox && m_batteryCloseDisplayHintIcon && m_batteryCloseDisplayHintLabel && m_batteryCloseDisplayFrame) { if ((((m_batteryCloseDisplayComboBox->currentData().toInt() > m_batterySleepComboBox->currentData().toInt()) && m_batterySleepComboBox->currentData().toInt() !=0) || (m_batteryCloseDisplayComboBox->currentData().toInt() == 0 && m_batterySleepComboBox->currentData().toInt() != 0)) && m_isExistSuspend) { m_batteryCloseDisplayHintIcon->setVisible(true); m_batteryCloseDisplayHintLabel->setVisible(true); m_batteryCloseDisplayFrame->setMinimumHeight(100); } else { m_batteryCloseDisplayHintIcon->setVisible(false); m_batteryCloseDisplayHintLabel->setVisible(false); m_batteryCloseDisplayFrame->setMinimumHeight(60); } } } void Power::hideComponent() { m_acCloseDisplayLine->setVisible(m_isExistSuspend); m_acSleepFrame->setVisible(m_isExistSuspend); // S2H 相关仅由 CanSuspendThenHibernate 决定 m_acHibernateFrame->setVisible(m_isExistS2H); m_acLineHibernate->setVisible(m_isExistS2H); if (mHasBat) { m_batteryHibernateFrame->setVisible(m_isExistS2H); m_batteryLineHibernate->setVisible(m_isExistS2H); } } void Power::hideComponentByConf2() { QString cloudPlatForm = QString(QLatin1String(kdk_system_get_hostCloudPlatform())); if (cloudPlatForm == "huawei") { m_acPowerFrame->setVisible(false); m_batteryPowerFrame->setVisible(false); m_batteryPlanTitleLabel->setVisible(false); Batterywidget->setVisible(false); mWakenPwdFrame->setVisible(false); mPowerKeyFrame->setVisible(false); mCloseLidFrame->setVisible(false); m_acSleepFrame->setVisible(false); line_2->setVisible(false); line_3->setVisible(false); m_acCloseDisplayLine->setVisible(false); mResourceFrame->setVisible(false); } } void Power::setEnableBySecurity() { QVariantMap ModuleMap = UkccCommon::getModuleHideStatus(); QString moduleSettings = ModuleMap.value("powerEnable").toString(); QStringList setItems = moduleSettings.split(","); qDebug() << Q_FUNC_INFO << moduleSettings; foreach (QString setItem, setItems) { QStringList item = setItem.split(":"); if (item.size() != 2) { continue; } qDebug() << "set item Name: " << item.at(0); if (item.at(0) == "mSleepPwdFrame") { mSleepPwdFrame->setEnabled(item.at(1) == "true"); } if (item.at(0) == "mWakenPwdFrame") { mWakenPwdFrame->setEnabled(item.at(1) == "true"); } } } QString Power::translationPath() const { return QString(QM_FILES_INSTALL_PATH) + "%1.ts"; } QFrame* Power::createAcSectionWidget(QWidget *parent) { m_acPowerSettingsLabel = new KLabel(parent); m_acPowerSettingsLabel->setContentsMargins(16, 0, 0, 0); m_acPowerSettingsLabel->setText(tr("using AC power")); mverticalLayout->addWidget(m_acPowerSettingsLabel); m_acPowerSettingsFrame = new QFrame(parent); m_acPowerSettingsFrame->setMinimumSize(QSize(550, 0)); m_acPowerSettingsFrame->setMaximumSize(QSize(16777215, 16777215)); m_acPowerSettingsFrame->setFrameShape(QFrame::Box); m_acPowerSettingsLayout = new QVBoxLayout(m_acPowerSettingsFrame); m_acPowerSettingsLayout->setContentsMargins(0, 0, 0, 0); m_acPowerSettingsLayout->setSpacing(0); // 关闭显示器 m_acCloseDisplayFrame = new QFrame(m_acPowerSettingsFrame); setFrame_Noframe(m_acCloseDisplayFrame); QVBoxLayout *vCloseLayout = new QVBoxLayout(m_acCloseDisplayFrame); QHBoxLayout *mainCloseLayout = new QHBoxLayout(); vCloseLayout->setContentsMargins(16, 10, 16, 10); m_acCloseDisplayLabel = new QLabel(m_acCloseDisplayFrame); m_acCloseDisplayLabel->setFixedWidth(550); m_acCloseDisplayComboBox = new QComboBox(m_acCloseDisplayFrame); m_acCloseDisplayComboBox->setObjectName("close"); m_acCloseDisplayComboBox->setMinimumWidth(200); mainCloseLayout->addWidget(m_acCloseDisplayLabel); mainCloseLayout->addWidget(m_acCloseDisplayComboBox); vCloseLayout->addLayout(mainCloseLayout); QHBoxLayout* hintLayout = new QHBoxLayout(); m_acCloseDisplayHintIcon = new QLabel; m_acCloseDisplayHintIcon->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(QSize(16, 16))); m_acCloseDisplayHintLabel = new LightLabel(tr("The system will sleep before turning off the display")); hintLayout->addWidget(m_acCloseDisplayHintIcon); hintLayout->addWidget(m_acCloseDisplayHintLabel); hintLayout->addStretch(); vCloseLayout->addLayout(hintLayout); m_acPowerSettingsLayout->addWidget(m_acCloseDisplayFrame); m_acCloseDisplayLine = setLine(m_acPowerSettingsFrame); m_acPowerSettingsLayout->addWidget(m_acCloseDisplayLine); // 睡眠 m_acSleepFrame = new QFrame(m_acPowerSettingsFrame); setFrame_Noframe(m_acSleepFrame); QVBoxLayout *vSleepLayout = new QVBoxLayout(m_acSleepFrame); QHBoxLayout *mainSleepLayout = new QHBoxLayout(); vSleepLayout->setContentsMargins(16, 0, 16, 0); m_acSleepLabel = new QLabel(m_acSleepFrame); m_acSleepLabel->setFixedWidth(550); m_acSleepComboBox = new QComboBox(m_acSleepFrame); m_acSleepComboBox->setObjectName("sleep"); m_acSleepComboBox->setMinimumWidth(200); mainSleepLayout->addWidget(m_acSleepLabel); mainSleepLayout->addWidget(m_acSleepComboBox); vSleepLayout->addLayout(mainSleepLayout); m_acPowerSettingsLayout->addWidget(m_acSleepFrame); m_acSleepLine = setLine(m_acPowerSettingsFrame); m_acPowerSettingsLayout->addWidget(m_acSleepLine); //S32S4 m_acHibernateFrame = new QFrame(m_acPowerSettingsFrame); setFrame_Noframe(m_acHibernateFrame); QHBoxLayout *m_acHibernateLayout = new QHBoxLayout(m_acHibernateFrame); m_acHibernateLayout->setContentsMargins(16, 0, 16, 0); m_acHibernateLabel = new QLabel(m_acHibernateFrame); m_acHibernateLabel->setFixedSize(550,59); m_acHibernateComboBox = new QComboBox(m_acHibernateFrame); m_acHibernateComboBox->setObjectName("hibernate"); m_acHibernateComboBox->setMinimumWidth(200); m_acHibernateLayout->addWidget(m_acHibernateLabel); m_acHibernateLayout->addWidget(m_acHibernateComboBox); m_acPowerSettingsLayout->addWidget(m_acHibernateFrame); m_acLineHibernate = setLine(m_acPowerSettingsFrame); m_acPowerSettingsLayout->addWidget(m_acLineHibernate); // 电源计划 m_acPowerFrame = new QFrame(m_acPowerSettingsFrame); setFrame_Noframe(m_acPowerFrame); QHBoxLayout *acPowerLayout = new QHBoxLayout(m_acPowerFrame); acPowerLayout->setContentsMargins(16, 0, 16, 0); m_acPowerLabel = new QLabel(m_acPowerFrame); m_acPowerLabel->setFixedSize(550,60); m_acPowerComboBox = new QComboBox(m_acPowerFrame); m_acPowerComboBox->setObjectName("powermode"); m_acPowerComboBox->setMinimumWidth(200); acPowerLayout->addWidget(m_acPowerLabel); acPowerLayout->addWidget(m_acPowerComboBox); m_acPowerSettingsLayout->addWidget(m_acPowerFrame); return m_acPowerSettingsFrame; } QFrame* Power::createBatterySectionWidget(QWidget *parent) { m_batteryPowerSettingsTitleLabel = new KLabel(parent); m_batteryPowerSettingsTitleLabel->setContentsMargins(16, 0, 0, 0); m_batteryPowerSettingsTitleLabel->setText(tr("using battery")); mverticalLayout->addWidget(m_batteryPowerSettingsTitleLabel); m_batteryPowerSettingsFrame = new QFrame(parent); m_batteryPowerSettingsFrame->setMinimumSize(QSize(550, 0)); m_batteryPowerSettingsFrame->setMaximumSize(QSize(16777215, 16777215)); m_batteryPowerSettingsFrame->setFrameShape(QFrame::Box); m_batteryPowerSettingsLayout = new QVBoxLayout(m_batteryPowerSettingsFrame); m_batteryPowerSettingsLayout->setContentsMargins(0, 0, 0, 0); m_batteryPowerSettingsLayout->setSpacing(0); // 关闭显示器 m_batteryCloseDisplayFrame = new QFrame(m_batteryPowerSettingsFrame); setFrame_Noframe(m_batteryCloseDisplayFrame); QVBoxLayout *vCloseLayout = new QVBoxLayout(m_batteryCloseDisplayFrame); QHBoxLayout *mainCloseLayout = new QHBoxLayout(); vCloseLayout->setContentsMargins(16, 10, 16, 10); m_batteryCloseDisplayLabel = new QLabel(m_batteryCloseDisplayFrame); m_batteryCloseDisplayLabel->setFixedWidth(550); m_batteryCloseDisplayComboBox = new QComboBox(m_batteryCloseDisplayFrame); m_batteryCloseDisplayComboBox->setObjectName("close"); m_batteryCloseDisplayComboBox->setMinimumWidth(200); mainCloseLayout->addWidget(m_batteryCloseDisplayLabel); mainCloseLayout->addWidget(m_batteryCloseDisplayComboBox); vCloseLayout->addLayout(mainCloseLayout); QHBoxLayout* hintLayout = new QHBoxLayout(); m_batteryCloseDisplayHintIcon = new QLabel; m_batteryCloseDisplayHintIcon->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(QSize(16, 16))); m_batteryCloseDisplayHintLabel = new LightLabel(tr("The system will sleep before turning off the display")); hintLayout->addWidget(m_batteryCloseDisplayHintIcon); hintLayout->addWidget(m_batteryCloseDisplayHintLabel); hintLayout->addStretch(); vCloseLayout->addLayout(hintLayout); m_batteryPowerSettingsLayout->addWidget(m_batteryCloseDisplayFrame); m_batteryCloseDisplayLine = setLine(m_batteryPowerSettingsFrame); m_batteryPowerSettingsLayout->addWidget(m_batteryCloseDisplayLine); //S32S4 m_batteryHibernateFrame = new QFrame(m_batteryPowerSettingsFrame); setFrame_Noframe(m_batteryHibernateFrame); QHBoxLayout *m_batteryHibernateLayout = new QHBoxLayout(m_batteryHibernateFrame); m_batteryHibernateLayout->setContentsMargins(16, 0, 16, 0); m_batteryHibernateLabel = new QLabel(m_batteryHibernateFrame); m_batteryHibernateLabel->setFixedSize(550,59); m_batteryHibernateComboBox = new QComboBox(m_batteryHibernateFrame); m_batteryHibernateComboBox->setObjectName("hibernate"); m_batteryHibernateComboBox->setMinimumWidth(200); m_batteryHibernateLayout->addWidget(m_batteryHibernateLabel); m_batteryHibernateLayout->addWidget(m_batteryHibernateComboBox); m_batteryPowerSettingsLayout->addWidget(m_batteryHibernateFrame); m_batteryLineHibernate = setLine(m_batteryPowerSettingsFrame); m_batteryPowerSettingsLayout->addWidget(m_batteryLineHibernate); // 睡眠 m_batterySleepFrame = new QFrame(m_batteryPowerSettingsFrame); setFrame_Noframe(m_batterySleepFrame); QVBoxLayout *vSleepLayout = new QVBoxLayout(m_batterySleepFrame); QHBoxLayout *mainSleepLayout = new QHBoxLayout(); vSleepLayout->setContentsMargins(16, 0, 16, 0); m_batterySleepLabel = new QLabel(m_batterySleepFrame); m_batterySleepLabel->setFixedWidth(550); m_batterySleepComboBox = new QComboBox(m_batterySleepFrame); m_batterySleepComboBox->setObjectName("sleep"); m_batterySleepComboBox->setMinimumWidth(200); mainSleepLayout->addWidget(m_batterySleepLabel); mainSleepLayout->addWidget(m_batterySleepComboBox); vSleepLayout->addLayout(mainSleepLayout); m_batteryPowerSettingsLayout->addWidget(m_batterySleepFrame); m_batterySleepLine = setLine(m_batteryPowerSettingsFrame); m_batteryPowerSettingsLayout->addWidget(m_batterySleepLine); // 电池计划 m_batteryPowerFrame = new QFrame(m_batteryPowerSettingsFrame); setFrame_Noframe(m_batteryPowerFrame); QHBoxLayout *batteryPowerLayout = new QHBoxLayout(m_batteryPowerFrame); batteryPowerLayout->setContentsMargins(16, 0, 16, 0); m_batteryPowerLabel = new QLabel(m_batteryPowerFrame); m_batteryPowerLabel->setFixedSize(550,59); m_batteryPowerComboBox = new QComboBox(m_batteryPowerFrame); m_batteryPowerComboBox->setObjectName("batterymode"); m_batteryPowerComboBox->setMinimumWidth(200); batteryPowerLayout->addWidget(m_batteryPowerLabel); batteryPowerLayout->addWidget(m_batteryPowerComboBox); m_batteryPowerSettingsLayout->addWidget(m_batteryPowerFrame); return m_batteryPowerSettingsFrame; }ukui-power-manager/power/interface.h0000664000175000017500000000426415167661430016503 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef INTERFACE_H #define INTERFACE_H #include #include #include #include class QString; class QWidget; class QStringLiteral; enum FunType { ACCOUNT, SYSTEM, DEVICES, NETWORK, PERSONALIZED, DATETIME, UPDATE, SECURITY, APPLICATION, SEARCH_F, COMMONINFO, //NOTICEANDTASKS, TOTALMODULES, }; class CommonInterface{ public: virtual ~CommonInterface(){} virtual QString plugini18nName() = 0; // 插件名字 virtual int pluginTypes() = 0; // 插件类型 virtual QWidget * pluginUi() = 0; // 插件主界面 virtual bool isShowOnHomePage() const = 0; // 是否显示在首页 virtual QIcon icon() const = 0; // 图标 virtual bool isEnable() const = 0; // 插件是否启用 virtual const QString name() const = 0; // 模块名称 virtual QString translationPath() const { // 获取多语言文件路径,用于搜索 return QStringLiteral("/usr/share/ukui-control-center/shell/res/i18n/%1.ts"); } QStandardItem *pluginBtn = nullptr; virtual void plugin_leave() { return ; } }; #define CommonInterface_iid "org.ukcc.CommonInterface" Q_DECLARE_INTERFACE(CommonInterface, CommonInterface_iid) #endif // INTERFACE_H ukui-power-manager/power/power.pro0000664000175000017500000000347115167661430016247 0ustar fengfengQT += widgets dbus gui core TEMPLATE = lib CONFIG += plugin TARGET = $$qtLibraryTarget(power) DESTDIR = ../.. target.path = $$[QT_INSTALL_LIBS]/ukui-control-center INSTALLS += target INCLUDEPATH += \ $$PROJECT_ROOTDIR \ /usr/include/ukcc/interface \ /usr/include/ukcc/widgets \ /usr/include/ukcc LIBS += -L$$[QT_INSTALL_LIBS] -lgsettings-qt6 -lupower-glib -lukcc CONFIG += \ link_pkgconfig \ c++11 PKGCONFIG += gsettings-qt6 \ gio-2.0 \ gio-unix-2.0 \ upower-glib \ kysdk-qtwidgets \ kysdk-sysinfo FORMS += HEADERS += \ power.h \ powermacrodata.h\ interface.h SOURCES += \ power.cpp\ TRANSLATIONS += \ translations/zh_CN.ts \ translations/bo_CN.ts \ translations/zh_HK.ts \ translations/en_US.ts \ translations/ug.ts \ translations/ky.ts \ translations/kk.ts \ translations/mn.ts \ translations/tr.ts QM_FILES_INSTALL_PATH = /usr/share/ukui-power-manager/power/translations/ # CONFIG += lrelase not work for qt5.6, add those from lrelease.prf for compatibility qtPrepareTool(QMAKE_LRELEASE, lrelease) lrelease.name = lrelease lrelease.input = TRANSLATIONS lrelease.output = ${QMAKE_FILE_IN_BASE}.qm lrelease.commands = $$QMAKE_LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_OUT} lrelease.CONFIG = no_link QMAKE_EXTRA_COMPILERS += lrelease PRE_TARGETDEPS += compiler_lrelease_make_all for (translation, TRANSLATIONS) { translation = $$basename(translation) QM_FILES += $$OUT_PWD/$$replace(translation, \\..*$, .qm) } qm_files.files = $$QM_FILES qm_files.path = $$QM_FILES_INSTALL_PATH qm_files.CONFIG = no_check_exist INSTALLS += qm_files DEFINES += QM_FILES_INSTALL_PATH='\\"$${QM_FILES_INSTALL_PATH}\\"' ukui-power-manager/power/powermacrodata.h0000664000175000017500000000647715167661430017563 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef POWERMACRODATA_H #define POWERMACRODATA_H #define UKUI_QUICK_OPERATION_PANEL "org.ukui.quick-operation.panel" #define ENERGYSAVINGMODE "energysavingmode" #define IDLE_DIM_AC "idle-dim-ac" #define IDLE_DIM_BA "idle-dim-battery" #define BRIGHTNESS_AC "brightness-ac" #define PROC_MANAGER "org.ukui.process-manager" #define RESOURCE_LIMIT_ENABLED "resource-limit-enabled" #define POWERMANAGER_SCHEMA "org.ukui.power-manager" #define ICONPOLICY "icon-policy" constexpr const char* HIBERNATE_COMPUTER_AC_KEY = "hibernateComputerAc"; constexpr const char* HIBERNATE_COMPUTER_BATT_KEY = "hibernateComputerBattery"; #define SLEEP_COMPUTER_AC_KEY "sleep-computer-ac" #define SLEEP_COMPUTER_BATT_KEY "sleep-computer-battery" #define SLEEP_DISPLAY_AC_KEY "sleep-display-ac" #define SLEEP_DISPLAY_BATT_KEY "sleep-display-battery" #define BUTTON_LID_AC_KEY "button-lid-ac" #define BUTTON_LID_BATT_KET "button-lid-battery" #define BUTTON_SUSPEND_KEY "button-suspend" #define BUTTON_POWER_KEY "button-power" #define IDLE_DIM_TIME_KEY "idle-dim-time" #define HIBERNATE_KEY "after-idle-action" #define PER_ACTION_KEY "percentage-action" #define ACTION_CRI_BTY "action-critical-battery" #define PER_ACTION_CRI "percentage-critical" #define POWER_POLICY_AC "power-policy-ac" #define POWER_POLICY_BATTARY "power-policy-battery" #define LOCK_BLANK_SCREEN "lock-blank-screen" #define PERCENTAGE_LOW "percentage-low" #define LOW_BATTERY_AUTO_SAVE "low-battery-auto-save" #define ON_BATTERY_AUTO_SAVE "on-battery-auto-save" #define DISPLAY_LEFT_TIME_OF_CHARGE_AND_DISCHARGE "dispalyLeftTimeOfChargeAndDischarge" #define SCREENSAVER_SCHEMA "org.ukui.screensaver" #define SLEEP_ACTIVATION_ENABLED "sleep-activation-enabled" #define CLOSE_ACTIVATION_ENABLED "close-activation-enabled" #define SCREENLOCK_LOCK_KEY "lock-enabled" #define SCREENLOCK_ACTIVE_KEY "idle-activation-enabled" #define PRESENT_VALUE "present" #define ALWAYS_VALUE "always" #define CHARGE_VALUE "charge" #define SESSION_SCHEMA "org.ukui.session" #define IDLE_DELAY_KEY "idle-delay" #define FIXES 60 #define PERSONALSIE_SCHEMA "org.ukui.control-center.personalise" #define PERSONALSIE_POWER_KEY "custompower" #define ISWHICHCHECKED "ischecked" #define POWER_MODE "power-mode" #define STYLE_FONT_SCHEMA "org.ukui.style" #endif // POWERMACRODATA_H ukui-power-manager/power/power.h0000664000175000017500000001716315167661430015701 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef POWER_H #define POWER_H #include #include #include #include #include #include #include #include #include #include "interface.h" #include "comboxframe.h" #include "lightlabel.h" #include #include "kswitchbutton.h" using namespace kdk; namespace Ui { class Power; } class Power : public QObject, CommonInterface { Q_OBJECT Q_PLUGIN_METADATA(IID "org.ukcc.CommonInterface") Q_INTERFACES(CommonInterface) public: explicit Power(); ~Power(); public: QString plugini18nName() Q_DECL_OVERRIDE; int pluginTypes() Q_DECL_OVERRIDE; QWidget *pluginUi() Q_DECL_OVERRIDE; const QString name() const Q_DECL_OVERRIDE; bool isShowOnHomePage() const Q_DECL_OVERRIDE; QIcon icon() const Q_DECL_OVERRIDE; bool isEnable() const Q_DECL_OVERRIDE; QString translationPath() const Q_DECL_OVERRIDE; public: void initUI(QWidget *widget); void initInterface(); void retranslateUi(); void resetui(); void setupComponent(); void setupConnect(); void initCustomPlanStatus(); void isLidPresent(); bool isHibernateSupply(); bool isSuspend2HibernateSupply(); bool isSuspendSupply(); bool isExitBattery(); bool QLabelSetText(QLabel *label, QString string); void clearAutoItem(QVBoxLayout *mLyt); void setFrame_Noframe(QFrame *frame); QFrame *setLine(QFrame *frame); void setHintLable(); void hideComponent(); void hideComponentByConf2(); private: QWidget *pluginWidget; QGSettings *settings; QGSettings *sessionSetting; QGSettings *stylesettings; QGSettings *sessionsettings; QGSettings *screensettings; QGSettings *m_centerSettings; QGSettings *m_qsettings; QGSettings *mProcManagerSettings = nullptr; QDBusInterface *hostLightStripDbus = nullptr; bool isSupportHostLight = false; QString pluginName; int pluginType; KLabel *m_customTitleLabel = nullptr; KLabel *m_batteryPlanTitleLabel = nullptr; KLabel *m_acPowerSettingsLabel = nullptr; KLabel *m_batteryPowerSettingsTitleLabel = nullptr; QLabel *mSleepPwdLabel; QLabel *mWakenPwdLabel; QLabel *mPowerKeyLabel; QLabel *m_acCloseDisplayLabel = nullptr; QLabel *m_batteryCloseDisplayLabel = nullptr; QLabel *m_acCloseDisplayHintIcon = nullptr; QLabel *m_batteryCloseDisplayHintIcon = nullptr; LightLabel *m_acCloseDisplayHintLabel = nullptr; LightLabel *m_batteryCloseDisplayHintLabel = nullptr; QLabel *m_acSleepLabel = nullptr; QLabel *m_batterySleepLabel = nullptr; QLabel *m_acHibernateLabel = nullptr; QLabel *m_batteryHibernateLabel = nullptr; QLabel *mCloseLidLabel; QLabel *mHostLightLabel; QLabel *mResourceLabel; QLabel *m_remainingTimeLabel = nullptr; QLabel *m_acPowerLabel = nullptr; QLabel *m_batteryPowerLabel = nullptr; QLabel *mDarkenLabel; QLabel *mLowpowerLabel1; QLabel *mLowpowerLabel2; QLabel *mNoticeLabel; QLabel *mLowSaveLabel; QLabel *mBatterySaveLabel; QLabel *mDisplayTimeLabel; LightLabel *m_resourceDetailLabel = nullptr; QFrame *Powerwidget; QFrame *BlankSleepwidget; QFrame *PowerPlanwidget; QFrame *Batterywidget; QFrame *mSleepPwdFrame; QFrame *mWakenPwdFrame; QFrame *mPowerKeyFrame; QFrame *m_acCloseDisplayFrame = nullptr; QFrame *m_batteryCloseDisplayFrame = nullptr; QFrame *m_acSleepFrame = nullptr; QFrame *m_batterySleepFrame = nullptr; QFrame *m_acHibernateFrame = nullptr; QFrame *m_batteryHibernateFrame = nullptr; QFrame *mCloseLidFrame; QFrame *mHostLightFrame; QFrame *mResourceFrame; QFrame *m_remainingTimeFrame = nullptr; QFrame *m_acPowerSettingsFrame = nullptr; QFrame *m_batteryPowerSettingsFrame = nullptr; QFrame *mBatteryPlanFrame; QFrame *m_acPowerFrame = nullptr; QFrame *m_batteryPowerFrame = nullptr; QFrame *mDarkenFrame; QFrame *mLowpowerFrame; QFrame *mNoticeLFrame; QFrame *mLowSaveFrame; QFrame *mBatterySaveFrame; QFrame *mDisplayTimeFrame; QFrame* createAcSectionWidget(QWidget *parent); QFrame* createBatterySectionWidget(QWidget *parent); QFrame *line_1; QFrame *line_2; QFrame *line_3; QFrame *m_acCloseDisplayLine; QFrame *m_acSleepLine; QFrame *m_acLineHibernate = nullptr; QFrame *m_batteryLineHibernate = nullptr; QFrame *line_6; QFrame *line_7; QFrame *line_8; QFrame *line_9; QFrame *line_10; QFrame *line_11; QFrame *line_12; QFrame *m_batteryCloseDisplayLine; QFrame *m_batterySleepLine; QSpacerItem *mItem; QComboBox *mPowerKeyComboBox; QComboBox *m_acCloseDisplayComboBox = nullptr; QComboBox *m_batteryCloseDisplayComboBox = nullptr; QComboBox *m_acSleepComboBox = nullptr; QComboBox *m_batterySleepComboBox = nullptr; QComboBox *m_acHibernateComboBox = nullptr; QComboBox *m_batteryHibernateComboBox = nullptr; QComboBox *mCloseLidComboBox; QComboBox *m_acPowerComboBox = nullptr; QComboBox *m_batteryPowerComboBox = nullptr; QComboBox *mDarkenComboBox; QComboBox *m_lowpowerComboBox1; QComboBox *mLowpowerComboBox2; QComboBox *mNoticeComboBox; KSwitchButton *mSleepPwdBtn; KSwitchButton *mResourceSButton; KSwitchButton *m_remainingTimeSwitch = nullptr; KSwitchButton *mWakenPwdBtn; KSwitchButton *mHostLightSButton; KSwitchButton *mLowSaveBtn; KSwitchButton *mBatterySaveBtn; KSwitchButton *mDisplayTimeBtn; QButtonGroup *mPowerBtnGroup; QSpacerItem *verticalSpacer; QSpacerItem *verticalSpacer_1; QSpacerItem *verticalSpacer_2; QStringList buttonStringList; QStringList sleepStringList; QStringList sleepStringList_battery; QStringList closeStringList; QStringList closeStringList_battery; QStringList acHibernateStringList; QStringList batteryHibernateStringList; QStringList closeLidStringList; QStringList PowerplanStringList; QStringList BatteryplanStringList; QStringList DarkenStringList; QStringList LowpowerStringList; QStringList mKeys; QVBoxLayout *BatteryLayout; QVBoxLayout *PowerLayout; QVBoxLayout *m_acPowerSettingsLayout = nullptr; QVBoxLayout *m_batteryPowerSettingsLayout = nullptr; QVBoxLayout *mverticalLayout; QDBusInterface *mHibernateInterface = nullptr; bool mFirstLoad; bool mIsExistLid; bool m_isExistHibernate; // 休眠 bool m_isExistSuspend; // 睡眠 bool mHasBat; bool m_isExistS2H; private slots: void setVisibleBySecurity(); void setEnableBySecurity(); private: bool kconf2Enable(const QString &cloudPlatForm) const; }; #endif // POWER_H ukui-power-manager/.clang-format0000664000175000017500000001771015167661415015614 0ustar fengfeng--- # 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto Language: Cpp # BasedOnStyle: WebKit # 访问说明符(public、private等)的偏移 AccessModifierOffset: -4 # 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行) AlignAfterOpenBracket: AlwaysBreak # 连续赋值时,对齐所有等号 AlignConsecutiveAssignments: false # 连续声明时,对齐所有声明的变量名 AlignConsecutiveDeclarations: false # 左对齐逃脱换行(使用反斜杠换行)的反斜杠 AlignEscapedNewlines: Right # 水平对齐二元和三元表达式的操作数 AlignOperands: true # 对齐连续的尾随的注释 AlignTrailingComments: true # 允许函数声明的所有参数在放在下一行 AllowAllParametersOfDeclarationOnNextLine: true # 允许短的块放在同一行 AllowShortBlocksOnASingleLine: false # 允许短的case标签放在同一行 AllowShortCaseLabelsOnASingleLine: false # 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All AllowShortFunctionsOnASingleLine: Empty # 允许短的if语句保持在同一行 AllowShortIfStatementsOnASingleLine: false # 允许短的循环保持在同一行 AllowShortLoopsOnASingleLine: false # 总是在定义返回类型后换行(deprecated) AlwaysBreakAfterDefinitionReturnType: None # 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数), # AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义) AlwaysBreakAfterReturnType: None # 总是在多行string字面量前换行 AlwaysBreakBeforeMultilineStrings: false # 总是在template声明后换行 AlwaysBreakTemplateDeclarations: true # false表示函数实参要么都在同一行,要么都各自一行 BinPackArguments: false # false表示所有形参要么都在同一行,要么都各自一行 BinPackParameters: false # 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效 BraceWrapping: # class定义后面 AfterClass: true # 控制语句后面 AfterControlStatement: false # enum定义后面 AfterEnum: true # 函数定义后面 AfterFunction: true # 命名空间定义后面 AfterNamespace: true # ObjC定义后面 AfterObjCDeclaration: false # struct定义后面 AfterStruct: true # union定义后面 AfterUnion: true # extern 定义后面 AfterExternBlock: true # catch之前 BeforeCatch: false # else 之前 BeforeElse: false # 缩进大括号 IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true # 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行) BreakBeforeBinaryOperators: All # 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义,与Attach类似), # Mozilla(除枚举、函数、记录定义,与Attach类似), Stroustrup(除函数定义、catch、else,与Attach类似), # Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom # 注:这里认为语句块也属于函数 BreakBeforeBraces: Custom # 继承列表的逗号前换行 BreakBeforeInheritanceComma: false # 在三元运算符前换行 BreakBeforeTernaryOperators: true # 在构造函数的初始化列表的逗号前换行 BreakConstructorInitializersBeforeComma: false # 初始化列表前换行 BreakConstructorInitializers: BeforeComma # Java注解后换行 BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true # 每行字符的限制,0表示没有限制 ColumnLimit: 120 # 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变 CommentPragmas: '^ IWYU pragma:' # 紧凑 命名空间 CompactNamespaces: false # 构造函数的初始化列表要么都在同一行,要么都各自一行 ConstructorInitializerAllOnOneLineOrOnePerLine: true # 构造函数的初始化列表的缩进宽度 ConstructorInitializerIndentWidth: 4 # 延续的行的缩进宽度 ContinuationIndentWidth: 4 # 去除C++11的列表初始化的大括号{后和}前的空格 Cpp11BracedListStyle: false # 继承最常用的指针和引用的对齐方式 DerivePointerAlignment: false # 关闭格式化 DisableFormat: false # 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental) ExperimentalAutoDetectBinPacking: false # 固定命名空间注释 FixNamespaceComments: true # 需要被解读为foreach循环而不是函数调用的宏 ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Preserve # 对#include进行排序,匹配了某正则表达式的#include拥有对应的优先级,匹配不到的则默认优先级为INT_MAX(优先级越小排序越靠前), # 可以定义负数优先级从而保证某些#include永远在最前面 IncludeCategories: - Regex: '^"(llvm|llvm-c|clang|clang-c)/' Priority: 2 - Regex: '^(<|"(gtest|gmock|isl|json)/)' Priority: 3 - Regex: '.*' Priority: 1 IncludeIsMainRegex: '(Test)?$' # 缩进case标签 IndentCaseLabels: true IndentPPDirectives: None # 缩进宽度 IndentWidth: 4 # 函数返回类型换行时,缩进函数声明或函数定义的函数名 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true # 保留在块开始处的空行 KeepEmptyLinesAtTheStartOfBlocks: true # 开始一个块的宏的正则表达式 MacroBlockBegin: '' # 结束一个块的宏的正则表达式 MacroBlockEnd: '' # 连续空行的最大数量 MaxEmptyLinesToKeep: 1 # 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All NamespaceIndentation: Inner # 使用ObjC块时缩进宽度 ObjCBlockIndentWidth: 4 # 在ObjC的@property后添加一个空格 ObjCSpaceAfterProperty: true # 在ObjC的protocol列表前添加一个空格 ObjCSpaceBeforeProtocolList: true PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 19 # 在一个注释中引入换行的penalty PenaltyBreakComment: 300 # 第一次在<<前换行的penalty PenaltyBreakFirstLessLess: 120 # 在一个字符串字面量中引入换行的penalty PenaltyBreakString: 1000 # 对于每个在行字符数限制之外的字符的penalty PenaltyExcessCharacter: 1000000 # 将函数的返回类型放到它自己的行的penalty PenaltyReturnTypeOnItsOwnLine: 60 # 指针和引用的对齐: Left, Right, Middle PointerAlignment: Right #RawStringFormats: # - Delimiter: pb # Language: TextProto # BasedOnStyle: google # 允许重新排版注释 ReflowComments: true # 允许排序#include SortIncludes: false SortUsingDeclarations: true # 在C风格类型转换后添加空格 SpaceAfterCStyleCast: false # 模板关键字后面添加空格 SpaceAfterTemplateKeyword: true # 在赋值运算符之前添加空格 SpaceBeforeAssignmentOperators: true # 开圆括号之前添加一个空格: Never, ControlStatements, Always SpaceBeforeParens: ControlStatements # 在空的圆括号中添加空格 SpaceInEmptyParentheses: false # 在尾随的评论前添加的空格数(只适用于//) SpacesBeforeTrailingComments: 1 # 在尖括号的<后和>前添加空格 SpacesInAngles: false # 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格 SpacesInContainerLiterals: true # 在C风格类型转换的括号中添加空格 SpacesInCStyleCastParentheses: false # 在圆括号的(后和)前添加空格 SpacesInParentheses: false # 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响 SpacesInSquareBrackets: false # 标准: Cpp03, Cpp11, Auto Standard: Cpp11 # tab宽度 TabWidth: 4 # 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always UseTab: Never ... ukui-power-manager/readme.md0000664000175000017500000000036415167661415015015 0ustar fengfeng## dbus 服务 ``` 用于提权 使用方法: mkdir build make -j8 sudo make install //这样会讲service文件安装到系统目录下 调用exitService接口退出 //或者重启,否则修改无法生效(注销也不生效) ``` ukui-power-manager/shared/0000775000175000017500000000000015167661430014476 5ustar fengfengukui-power-manager/shared/include/0000775000175000017500000000000015167661430016121 5ustar fengfengukui-power-manager/shared/include/dmi_chassis_type.h0000664000175000017500000000245615167661430021630 0ustar fengfeng/* * Copyright 2025 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once enum class DmiChassisType { Other = 1, Unknown, Desktop, LowProfileDesktop, PizzaBox, MinTower, Tower, Portable, Laptop, Notebook, HandHeld, DockingStation, AllInOne, SubNotebook, SpaceSaving, LunchBox, MainServerChassis, ExpansionChassis, SubChassis, BusExpansionChassis, PeripheralChassis, RAIDChassis, RackMountChassis, SealedCasePC, Multisystem, CompactPCI, AdvancedTCA, Blade, BladeEnclosing, Tablet, Convertible, Detachable, IoTGateway, EmbeddedPC, MiniPC, StickPC };ukui-power-manager/doc/0000775000175000017500000000000015167661415014000 5ustar fengfengukui-power-manager/doc/性能测试注意事项.md0000664000175000017500000000112615167661415025056 0ustar fengfeng# 性能测试注意事项 ``` 1.连接电源【使用电池的情况下电源管理会更改调频策略】 2.控制面板设置电源计划为性能模式 如果控制面板-系统-电源-使用电源时的模式选择没有性能模式则需要手动设置【v10sp1 0820-1 版本暂时没有性能模式选项】 gsettings set org.ukui.power-manager power-policy-ac 0 3.控制面板-系统-电源-此时间段后关闭显示器 选为从不 4.控制面板-系统-电源-此时间段后进入睡眠 选为从不 5.控制面板-个性化-屏保-此时间段后开启屏保 选为从不 ``` ukui-power-manager/doc/schedules.md0000664000175000017500000000404015167661415016277 0ustar fengfeng## 计划表 ``` 计划8月份基本完成电源管理的改版工作 保证9月30号之前新版电源管理能够上线使用使用 具体时间节点: 电源显示界面: 0813 :ui改版,去除ui文件【处理中,由于新插入其他工作,预计延期】 0820 :新增消息通知类,用以处理极低电量,低电量等消息通知 0827 :托盘图标显示界面分离 0903 :快捷键亮度调节界面重写 电源管理事件调度后台: 0805 :电源管理基础 调研文档(第一阶段)基本结束(包括upower,亮度调节,cpu调频等)[基本完成] 0806 :亮度调节,cpu调频,关闭显示器的dbus服务接口完成 【亮度调节接口未完成,其他基本完成,demo未补充,预计0810之前完成】 0813 :电源管理事件调度中心核心代码编写完毕;gpu调频接口处理【已经开始着手处理,处理的时候务必保证功能稳定性】 0820 :电源管理基础 调研文档(第二阶段)结束。 电源管理后台( 事件分发,事件调度,策略修改) 代码联调 整机测试,分别在华为990笔记本,华为990台式机,华为9a0笔记本, 飞腾,鲲鹏,清华同方,龙芯4000,龙芯5000,联想机器联调功能。 (国产机器驱动书写未必符合规范,所以一定要) 0827 :新版电源管理后台满足全部设计稿中的功能 0903 :代码优化,编包等,使新版电源管理达到可上线的状态 0910 :电源管理评审,完善设计文档,需求文档 0917 :准备上线,全量测试 ``` ``` 0807备注: 为保证功能稳定性,计划采用逐步替换旧版功能的方式进行修改 预计上线的流程为: -> ui替换 -> 空闲-关闭显示器功能后台采用新版 【时间节点0813】 -> 空闲-all 采用新版 (包括cpu调频,暂不包括gpu调频)【时间节点0820】 -> 合盖处理 采用新版 ;监听电源键 采用新版【时间节点 0827】 -> 完全替换【0903】 -> gpu调频 低电量处理 【0910】 ``` ukui-power-manager/doc/设计文档.md0000664000175000017500000000003315167661415020665 0ustar fengfeng# 电源管理设计文档 ukui-power-manager/doc/电源管理需求文档.md0000664000175000017500000000351515167661415024743 0ustar fengfeng# 电源管理需求文档 ### 目录 ``` 1.托盘图标 2.任务栏上弹出窗口 3.亮度调节界面 4.消息通知 5.后台服务 6.upower封装 7.upower代码改动 8.低电量处理 9.文档输出 ``` ## 托盘图标 ``` 功能点罗列: 1.支持显示正确的图标 2.区分台式机与笔记本(台式机上不显示图标) 3.支持悬浮显示tooltip 4.支持右键弹出窗口 5.支持选择显示剩余充电时间 需求分析: 1.通过upower接口获取图标名称 2.通过upower获取电量 3.通过upower获取电量改变的信号 4.通过upower封装的接口获取剩余多久充满电(需要用upower封装的接口原因是原生接口数值波动过大) ``` ## 任务栏上弹出窗口 ``` 功能点罗列: 1.支持显示在正确的位置(包括多屏,并且需要监听屏幕改变) 2.支持透明度与毛玻璃效果 3.支持圆角阴影 4.支持跟随主题 5.支持跟随文字大小变化 6.界面内的图标与托盘图标保持一致 7.界面内的文字保持与托盘tooltip一致 ``` ## 亮度调节界面 ``` 功能点罗列: 1.支持透明度与毛玻璃效果 2.支持圆角阴影 3.支持跟随主题 4.支持图标高亮协议 5.支持双屏显示 6.绑定快捷键显示 7.禁止显示10%以下亮度 ``` ## 消息通知 ``` 功能点罗列 1.接收upower的信号和电量,进行消息通知 ``` ## 低电量处理 ``` 功能点罗列: 1.电池低电量之后自动进入省电模式 2.使用电池时自动进入节能模式 3.低电量通知 4.极低电量关机等功能 ``` ## 后台服务 ``` 功能点罗列: 一. 合盖处理 二. 关机键处理 三. 空闲处理 合盖处理 1. 选择合盖子之后的操作,调用相关接口即可 关机键处理 1. 选择关机键按下之后的操作即可 空闲处理 1.关闭显示器 2.睡眠/休眠 3.降低屏幕亮度 ```ukui-power-manager/man/0000775000175000017500000000000015167661430014003 5ustar fengfengukui-power-manager/man/ukui-power-manager-tray.10000664000175000017500000000143015167661415020562 0ustar fengfeng.TH ukui-power-manager-tray .SH NAME ukui-power-manager-tray \- The power-manager UI for the UKUI Desktop Environment .SH DESCRIPTION This module show power-manager widget This process is mainly for displaying the power management tray and the main interface after opening the tray icon. Currently, the main interface will show the user the current remaining power and remaining charging time. And provide users with an interface to enter the control panel to set related power operations. .SH "REPORTING BUGS" Report bugs to http://gitlab2.kylin.com/ukui/ukui-power-manager/issues .SH "SEE ALSO" .SS Ukui PowerManager documentation can be found under "Help" by right-clicking on \fBukui-power-manager\fR. Further information may also be available at: http://wiki.ukui-desktop.org/docs .P ukui-power-manager/man/ukui-powermanagement-service.10000664000175000017500000000136515167661415021677 0ustar fengfeng.TH ukui-power-management-server .SH NAME ukui-power-management-server \- The power-manager Dbus Server for the UKUI Desktop Environment .SH DESCRIPTION This module show power-manager Dbus Server This service provides corresponding interfaces for the power management background process, such as shutdown, hibernation, sleep, etc. The main corresponding interface is the corresponding interface provided by systemd. The service is treated as a SystemBus. .SH "REPORTING BUGS" Report bugs to http://gitlab2.kylin.com/ukui/ukui-power-manager/issues .SH "SEE ALSO" .SS Ukui PowerManager documentation can be found under "Help" by right-clicking on \fBukui-power-manager\fR. Further information may also be available at: http://wiki.ukui-desktop.org/docs .P ukui-power-manager/man/ukui-power-manager.20000664000175000017500000000140215167661430017602 0ustar fengfeng.TH ukui-power-manager 2 .SH 名称 ukui-power-manager \- ukui 桌面环境电源管理 .SH 描述 ukui 桌面环境电源管理指的是桌面环境中负责电源,电池,锁屏,关闭显示器,注销,重启,等接口调用逻辑的组件 .PP 其根本目的是为了功耗控制 .PP 实现以下功能 .PP 1.读取内核电池信息并显示 .PP 2.设置空闲n分钟后进入 休眠/睡眠/关闭显示器 等功能 .PP 3.设置合上盖子后 休眠/睡眠/关闭显示器等功能 .PP 4.设置低电量自动进入省电模式 .PP .SH "用户手册" http://kylin-desktop.gitee.io/doc/ukui/ukui-power-manager/ .PP .SH "疑问解答" 如果您有疑问,请在这里反馈,我们会及时进行解答 https://gitee.com/kylin-desktop/doc/issues .PP ukui-power-manager/man/ukui-powermanagement.10000664000175000017500000000137415167661415020241 0ustar fengfeng.TH ukui-powermanagement .SH NAME ukui-powermanagement \- The power-manager Daemon for the UKUI Desktop Environment .SH DESCRIPTION This module show power-manager Daemon This program is a background process of power management, which is mainly responsible for controlling the idle operation, closing operation, and low power operation of the operating system. And monitor the action of plugging and unplugging the power cord and perform corresponding operations. .SH "REPORTING BUGS" Report bugs to http://gitlab2.kylin.com/ukui/ukui-power-manager/issues .SH "SEE ALSO" .SS Ukui PowerManager documentation can be found under "Help" by right-clicking on \fBukui-power-manager\fR. Further information may also be available at: http://wiki.ukui-desktop.org/docs .P ukui-power-manager/man/ukui-upower.10000664000175000017500000000136115167661415016365 0ustar fengfeng.TH ukui-upower .SH NAME ukui-upower \- The power-manager Interface for the UKUI Desktop Environment .SH DESCRIPTION This module show power-manager Interface The purpose of this process is to encapsulate upower and provide desktop components with information about upower and battery-related information. And the battery information is processed, and the interfaces and signals are opened to the remaining components. The process service is SessionBus. .SH "REPORTING BUGS" Report bugs to http://gitlab2.kylin.com/ukui/ukui-power-manager/issues .SH "SEE ALSO" .SS Ukui PowerManager documentation can be found under "Help" by right-clicking on \fBukui-power-manager\fR. Further information may also be available at: http://wiki.ukui-desktop.org/docs .P ukui-power-manager/man/ukui-power-manager.10000664000175000017500000000136015167661415017607 0ustar fengfeng.TH ukui-power-manager .SH NAME ukui-power-manager \- The power-manager for the UKUI Desktop Environment .SH DESCRIPTION This module show power-manager Daemon This program is a background process of power management, which is mainly responsible for controlling the idle operation, closing operation, and low power operation of the operating system. And monitor the action of plugging and unplugging the power cord and perform corresponding operations. .SH "REPORTING BUGS" Report bugs to http://gitlab2.kylin.com/ukui/ukui-power-manager/issues .SH "SEE ALSO" .SS Ukui PowerManager documentation can be found under "Help" by right-clicking on \fBukui-power-manager\fR. Further information may also be available at: http://wiki.ukui-desktop.org/docs .P ukui-power-manager/ukui-power-manager-tray/0000775000175000017500000000000015167661430017724 5ustar fengfengukui-power-manager/ukui-power-manager-tray/divider.cpp0000664000175000017500000000222615167661430022060 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "divider.h" #include #include Divider::Divider(QWidget *parent) : QFrame(parent) { this->setFixedHeight(1); } void Divider::paintEvent(QPaintEvent *e) { QPainter p(this); QColor color = qApp->palette().color(QPalette::BrightText); color.setAlphaF(0.08); p.save(); p.setBrush(color); p.setPen(Qt::transparent); p.drawRoundedRect(this->rect(), 6, 6); p.restore(); return QFrame::paintEvent(e); } ukui-power-manager/ukui-power-manager-tray/xatom-helper.cpp0000664000175000017500000001564515167661430023050 0ustar fengfeng/* * KWin Style UKUI * * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: Yue Lan * */ #include #include #include "xatom-helper.h" #include #include #include // 静态变量:缓存 X11 Display static Display* g_x11Display = nullptr; // 辅助函数:获取 X11 Display static Display* getX11Display() { if (QGuiApplication::platformName() != "xcb") return nullptr; // 如果已经打开过,直接返回 if (g_x11Display) return g_x11Display; // 直接使用 X11 API 打开 Display g_x11Display = XOpenDisplay(nullptr); return g_x11Display; } static XAtomHelper *global_instance = nullptr; XAtomHelper *XAtomHelper::getInstance() { if (!global_instance) global_instance = new XAtomHelper; return global_instance; } bool XAtomHelper::isFrameLessWindow(int winId) { auto hints = getInstance()->getWindowMotifHint(winId); if (hints.flags == MWM_HINTS_DECORATIONS && hints.functions == 1) { return true; } return false; } bool XAtomHelper::isWindowDecorateBorderOnly(int winId) { return isWindowMotifHintDecorateBorderOnly(getInstance()->getWindowMotifHint(winId)); } bool XAtomHelper::isWindowMotifHintDecorateBorderOnly(const MotifWmHints &hint) { bool isDeco = false; if (hint.flags & MWM_HINTS_DECORATIONS && hint.flags != MWM_HINTS_DECORATIONS) { if (hint.decorations == MWM_DECOR_BORDER) isDeco = true; } return isDeco; } bool XAtomHelper::isUKUICsdSupported() { // fixme: return false; } bool XAtomHelper::isUKUIDecorationWindow(int winId) { if (m_ukuiDecorationAtion == None) return false; Display *display = getX11Display(); if (!display) return false; Atom type; int format; ulong nitems; ulong bytes_after; uchar *data; bool isUKUIDecoration = false; XGetWindowProperty(display, winId, m_ukuiDecorationAtion, 0, LONG_MAX, false, m_ukuiDecorationAtion, &type, &format, &nitems, &bytes_after, &data); if (type == m_ukuiDecorationAtion) { if (nitems == 1) { isUKUIDecoration = data[0]; } } return isUKUIDecoration; } UnityCorners XAtomHelper::getWindowBorderRadius(int winId) { UnityCorners corners; Display *display = getX11Display(); if (!display) return corners; Atom type; int format; ulong nitems; ulong bytes_after; uchar *data; if (m_unityBorderRadiusAtom != None) { XGetWindowProperty(display, winId, m_unityBorderRadiusAtom, 0, LONG_MAX, false, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &data); if (type == XA_CARDINAL) { if (nitems == 4) { corners.topLeft = static_cast(data[0]); corners.topRight = static_cast(data[1*sizeof (ulong)]); corners.bottomLeft = static_cast(data[2*sizeof (ulong)]); corners.bottomRight = static_cast(data[3*sizeof (ulong)]); } XFree(data); } } return corners; } void XAtomHelper::setWindowBorderRadius(int winId, const UnityCorners &data) { if (m_unityBorderRadiusAtom == None) return; Display *display = getX11Display(); if (!display) return; ulong corners[4] = {data.topLeft, data.topRight, data.bottomLeft, data.bottomRight}; XChangeProperty(display, winId, m_unityBorderRadiusAtom, XA_CARDINAL, 32, PropModeReplace, (const unsigned char *) &corners, sizeof (corners)/sizeof (corners[0])); } void XAtomHelper::setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight) { if (m_unityBorderRadiusAtom == None) return; Display *display = getX11Display(); if (!display) return; ulong corners[4] = {(ulong)topLeft, (ulong)topRight, (ulong)bottomLeft, (ulong)bottomRight}; XChangeProperty(display, winId, m_unityBorderRadiusAtom, XA_CARDINAL, 32, PropModeReplace, (const unsigned char *) &corners, sizeof (corners)/sizeof (corners[0])); } void XAtomHelper::setUKUIDecoraiontHint(int winId, bool set) { if (m_ukuiDecorationAtion == None) return; Display *display = getX11Display(); if (!display) return; XChangeProperty(display, winId, m_ukuiDecorationAtion, m_ukuiDecorationAtion, 32, PropModeReplace, (const unsigned char *) &set, 1); } void XAtomHelper::setWindowMotifHint(int winId, const MotifWmHints &hints) { if (m_unityBorderRadiusAtom == None) return; Display *display = getX11Display(); if (!display) return; XChangeProperty(display, winId, m_motifWMHintsAtom, m_motifWMHintsAtom, 32, PropModeReplace, (const unsigned char *)&hints, sizeof (MotifWmHints)/ sizeof (ulong)); } MotifWmHints XAtomHelper::getWindowMotifHint(int winId) { MotifWmHints hints; Display *display = getX11Display(); if (!display) return hints; if (m_unityBorderRadiusAtom == None) return hints; uchar *data; Atom type; int format; ulong nitems; ulong bytes_after; XGetWindowProperty(display, winId, m_motifWMHintsAtom, 0, sizeof (MotifWmHints)/sizeof (long), false, AnyPropertyType, &type, &format, &nitems, &bytes_after, &data); if (type == None) { return hints; } else { hints = *(MotifWmHints *)data; XFree(data); } return hints; } XAtomHelper::XAtomHelper(QObject *parent) : QObject(parent) { if (QGuiApplication::platformName() != "xcb") return; Display *display = getX11Display(); if (!display) return; m_motifWMHintsAtom = XInternAtom(display, "_MOTIF_WM_HINTS", true); m_unityBorderRadiusAtom = XInternAtom(display, "_UNITY_GTK_BORDER_RADIUS", false); m_ukuiDecorationAtion = XInternAtom(display, "_KWIN_UKUI_DECORAION", false); } Atom XAtomHelper::registerUKUICsdNetWmSupportAtom() { // fixme: return None; } void XAtomHelper::unregisterUKUICsdNetWmSupportAtom() { // fixme: } ukui-power-manager/ukui-power-manager-tray/divider.h0000664000175000017500000000165715167661415021537 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef DIVIDER_H #define DIVIDER_H #include class Divider : public QFrame { public: Divider(QWidget * parent = nullptr); ~Divider() = default; protected: void paintEvent(QPaintEvent *event); }; #endif // DIVIDER_H ukui-power-manager/ukui-power-manager-tray/xatom-helper.h0000664000175000017500000000625215167661430022507 0ustar fengfeng/* * KWin Style UKUI * * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: Yue Lan * */ #ifndef XATOMHELPER_H #define XATOMHELPER_H #include #include struct UnityCorners { ulong topLeft = 0; ulong topRight = 0; ulong bottomLeft = 0; ulong bottomRight = 0; }; typedef struct { ulong flags = 0; ulong functions = 0; ulong decorations = 0; long input_mode = 0; ulong status = 0; } MotifWmHints, MwmHints; #define MWM_HINTS_FUNCTIONS (1L << 0) #define MWM_HINTS_DECORATIONS (1L << 1) #define MWM_HINTS_INPUT_MODE (1L << 2) #define MWM_HINTS_STATUS (1L << 3) #define MWM_FUNC_ALL (1L << 0) #define MWM_FUNC_RESIZE (1L << 1) #define MWM_FUNC_MOVE (1L << 2) #define MWM_FUNC_MINIMIZE (1L << 3) #define MWM_FUNC_MAXIMIZE (1L << 4) #define MWM_FUNC_CLOSE (1L << 5) #define MWM_DECOR_ALL (1L << 0) #define MWM_DECOR_BORDER (1L << 1) #define MWM_DECOR_RESIZEH (1L << 2) #define MWM_DECOR_TITLE (1L << 3) #define MWM_DECOR_MENU (1L << 4) #define MWM_DECOR_MINIMIZE (1L << 5) #define MWM_DECOR_MAXIMIZE (1L << 6) #define MWM_INPUT_MODELESS 0 #define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1 #define MWM_INPUT_SYSTEM_MODAL 2 #define MWM_INPUT_FULL_APPLICATION_MODAL 3 #define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL #define MWM_TEAROFF_WINDOW (1L<<0) namespace UKUI { class Decoration; } class XAtomHelper : public QObject { friend class UKUI::Decoration; Q_OBJECT public: static XAtomHelper *getInstance(); static bool isFrameLessWindow(int winId); bool isWindowDecorateBorderOnly(int winId); bool isWindowMotifHintDecorateBorderOnly(const MotifWmHints &hint); bool isUKUICsdSupported(); bool isUKUIDecorationWindow(int winId); UnityCorners getWindowBorderRadius(int winId); void setWindowBorderRadius(int winId, const UnityCorners &data); void setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight); void setUKUIDecoraiontHint(int winId, bool set = true); void setWindowMotifHint(int winId, const MotifWmHints &hints); MotifWmHints getWindowMotifHint(int winId); private: explicit XAtomHelper(QObject *parent = nullptr); Atom registerUKUICsdNetWmSupportAtom(); void unregisterUKUICsdNetWmSupportAtom(); Atom m_motifWMHintsAtom = None; Atom m_unityBorderRadiusAtom = None; Atom m_ukuiDecorationAtion = None; }; #endif // XATOMHELPER_H ukui-power-manager/ukui-power-manager-tray/customstyle.cpp0000664000175000017500000005173315167661430023034 0ustar fengfeng/* * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. * * This program or library is free software; you can redistribute it * and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ #include "customstyle.h" #include #include #include //#if QT_CONFIG(toolbutton) /*以下代码是为了处理toolbutton 的箭头*/ static void drawArrow( const QStyle *style, const QStyleOptionToolButton *toolbutton, const QRect &rect, QPainter *painter, const QWidget *widget = 0) { QStyle::PrimitiveElement pe; switch (toolbutton->arrowType) { case Qt::LeftArrow: pe = QStyle::PE_IndicatorArrowLeft; break; case Qt::RightArrow: pe = QStyle::PE_IndicatorArrowRight; break; case Qt::UpArrow: pe = QStyle::PE_IndicatorArrowUp; break; case Qt::DownArrow: pe = QStyle::PE_IndicatorArrowDown; break; default: return; } QStyleOption arrowOpt = *toolbutton; arrowOpt.rect = rect; style->drawPrimitive(pe, &arrowOpt, painter, widget); } //#endif // QT_CONFIG(toolbutton) CustomStyle::CustomStyle(const QString &proxyStyleName, bool multileWins, QObject *parent) : QProxyStyle(proxyStyleName) { pluginName = proxyStyleName; multileWindow = multileWins; } CustomStyle::~CustomStyle() {} /*Draws the given control using the provided painter with the style options specified by option.*/ void CustomStyle::drawComplexControl( QStyle::ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, const QWidget *widget) const { // if(control == CC_ToolButton) // { // /// 我们需要获取ToolButton的详细信息,通过qstyleoption_cast可以得到 // /// 对应的option,通过拷贝构造函数得到一CustomStyle份备份用于绘制子控件 // /// 我们一般不用在意option是怎么得到的,大部分的Qt控件都能够提供了option的init方法 // } switch (cc) { case CC_ToolButton: if (const QStyleOptionToolButton *toolbutton = qstyleoption_cast(opt)) { QRect button, menuarea; button = proxy()->subControlRect(cc, toolbutton, SC_ToolButton, widget); menuarea = proxy()->subControlRect(cc, toolbutton, SC_ToolButtonMenu, widget); State bflags = toolbutton->state & ~State_Sunken; if (bflags & State_AutoRaise) { if (!(bflags & State_MouseOver) || !(bflags & State_Enabled)) { bflags &= ~State_Raised; } } State mflags = bflags; if (toolbutton->state & State_Sunken) { if (toolbutton->activeSubControls & SC_ToolButton) bflags |= State_Sunken; mflags |= State_Sunken; } QStyleOption tool = *toolbutton; if (toolbutton->subControls & SC_ToolButton) { if (bflags & (State_Sunken | State_On | State_Raised)) { tool.rect = button; tool.state = bflags; proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p, widget); } } if (toolbutton->state & State_HasFocus) { QStyleOptionFocusRect fr; fr.QStyleOption::operator=(*toolbutton); fr.rect.adjust(3, 3, -3, -3); if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup) fr.rect.adjust( 0, 0, -proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, toolbutton, widget), 0); proxy()->drawPrimitive(PE_FrameFocusRect, &fr, p, widget); } QStyleOptionToolButton label = *toolbutton; label.state = bflags; int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget); label.rect = button.adjusted(fw, fw, -fw, -fw); proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget); if (toolbutton->subControls & SC_ToolButtonMenu) { tool.rect = menuarea; tool.state = mflags; if (mflags & (State_Sunken | State_On | State_Raised)) proxy()->drawPrimitive(PE_IndicatorButtonDropDown, &tool, p, widget); proxy()->drawPrimitive(PE_IndicatorArrowDown, &tool, p, widget); } else if (toolbutton->features & QStyleOptionToolButton::HasMenu) { int mbi = proxy()->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget); QRect ir = toolbutton->rect; QStyleOptionToolButton newBtn = *toolbutton; newBtn.rect = QRect(ir.right() + 5 - mbi, ir.y() + ir.height() - mbi + 4, mbi - 6, mbi - 6); newBtn.rect = visualRect(toolbutton->direction, button, newBtn.rect); // proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, p, widget); } } return; default: break; } return QProxyStyle::drawComplexControl(cc, opt, p, widget); } /*下面对于CE_ToolButtonLabel 的处理是因为quicklaunch 插件出现了箭头*/ void CustomStyle::drawControl( QStyle::ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *widget) const { switch (element) { case CE_PushButton: if (const QStyleOptionButton *btn = qstyleoption_cast(opt)) { proxy()->drawControl(CE_PushButtonBevel, btn, p, widget); QStyleOptionButton subopt = *btn; subopt.rect = subElementRect(SE_PushButtonContents, btn, widget); proxy()->drawControl(CE_PushButtonLabel, &subopt, p, widget); } break; case CE_PushButtonBevel: { if (const QStyleOptionButton *btn = qstyleoption_cast(opt)) { QRect br = btn->rect; int dbi = proxy()->pixelMetric(PM_ButtonDefaultIndicator, btn, widget); if (btn->features & QStyleOptionButton::AutoDefaultButton) br.setCoords(br.left() + dbi, br.top() + dbi, br.right() - dbi, br.bottom() - dbi); QStyleOptionButton tmpBtn = *btn; tmpBtn.rect = br; drawPrimitive(PE_PanelButtonCommand, &tmpBtn, p, widget); return; // qDebug()<<" ************** PushButton *********************** "; // p->save(); // // painter->setRenderHint(QPainter::Antialiasing,true); // // painter->setPen(Qt::NoPen); // // painter->drawRoundedRect(option->rect,6,6); // if (opt->state & State_MouseOver) { // if (opt->state & State_Sunken) { // p->setRenderHint(QPainter::Antialiasing,true); // p->setPen(Qt::NoPen); // p->setBrush(QColor(0xff,0xff,0xff)); // p->drawRoundedRect(opt->rect.adjusted(2,2,-2,-2),6,6); // } else { // p->setRenderHint(QPainter::Antialiasing,true); // p->setPen(Qt::NoPen); // p->setBrush(QColor(0xff,0xff,0xff)); // p->drawRoundedRect(opt->rect.adjusted(2,2,-2,-2),6,6); // } // } // p->restore(); // return; } break; } case CE_ToolButtonLabel: { if (const QStyleOptionToolButton *toolbutton = qstyleoption_cast(opt)) { QRect rect = toolbutton->rect; int shiftX = 0; int shiftY = 0; // if (toolbutton->state & (State_Sunken | State_On)) { // shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, toolbutton, widget); // shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, toolbutton, widget); // } // Arrow type always overrules and is always shown bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow; if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty()) || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) { int alignment = Qt::AlignCenter | Qt::TextShowMnemonic; if (!proxy()->styleHint(SH_UnderlineShortcut, opt, widget)) alignment |= Qt::TextHideMnemonic; rect.translate(shiftX, shiftY); p->setFont(toolbutton->font); proxy()->drawItemText( p, rect, alignment, toolbutton->palette, opt->state & State_Enabled, toolbutton->text, QPalette::ButtonText); } else { QPixmap pm; QSize pmSize = toolbutton->iconSize; if (!toolbutton->icon.isNull()) { QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off; QIcon::Mode mode; if (!(toolbutton->state & State_Enabled)) mode = QIcon::Disabled; else if ((opt->state & State_MouseOver) && (opt->state & State_AutoRaise)) mode = QIcon::Active; else mode = QIcon::Normal; pm = toolbutton->icon.pixmap( widget->window()->windowHandle(), toolbutton->rect.size().boundedTo(toolbutton->iconSize), mode, state); pmSize = pm.size() / pm.devicePixelRatio(); } if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) { p->setFont(toolbutton->font); QRect pr = rect, tr = rect; int alignment = Qt::TextShowMnemonic; if (!proxy()->styleHint(SH_UnderlineShortcut, opt, widget)) alignment |= Qt::TextHideMnemonic; if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) { pr.setHeight(pmSize.height() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint() tr.adjust(0, pr.height() - 1, 0, -1); pr.translate(shiftX, shiftY); if (!hasArrow) { proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pm); } else { drawArrow(proxy(), toolbutton, pr, p, widget); } alignment |= Qt::AlignCenter; } else { pr.setWidth(pmSize.width() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint() tr.adjust(pr.width(), 0, 0, 0); pr.translate(shiftX, shiftY); if (!hasArrow) { proxy()->drawItemPixmap( p, QStyle::visualRect(opt->direction, rect, pr), Qt::AlignCenter, pm); } else { drawArrow(proxy(), toolbutton, pr, p, widget); } alignment |= Qt::AlignLeft | Qt::AlignVCenter; } tr.translate(shiftX, shiftY); // const QString text = d->toolButtonElideText(toolbutton, tr, alignment); proxy()->drawItemText( p, QStyle::visualRect(opt->direction, rect, tr), alignment, toolbutton->palette, toolbutton->state & State_Enabled, toolbutton->text, QPalette::ButtonText); } else { rect.translate(shiftX, shiftY); if (hasArrow) { drawArrow(proxy(), toolbutton, rect, p, widget); } else { proxy()->drawItemPixmap(p, rect, Qt::AlignCenter, pm); } } } } return; } default: break; } return QProxyStyle::drawControl(element, opt, p, widget); } void CustomStyle::drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const { return QProxyStyle::drawItemPixmap(painter, rectangle, alignment, pixmap); } void CustomStyle::drawItemText( QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const { return QProxyStyle::drawItemText(painter, rectangle, alignment, palette, enabled, text, textRole); } //绘制简单的颜色圆角等 void CustomStyle::drawPrimitive( QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { switch (element) { /*绘制 ToolButton * 任务栏的不同插件需要的样式存在差异 * 在同一个PE中有两个toolbutton 的样式 */ case PE_PanelButtonTool: { { painter->save(); painter->setRenderHint(QPainter::Antialiasing, true); painter->setPen(Qt::NoPen); painter->drawRoundedRect(option->rect, 6, 6); if (option->state & State_MouseOver) { if (option->state & State_Sunken) { // painter->setRenderHint(QPainter::Antialiasing,true); // painter->setPen(Qt::NoPen); // painter->setBrush(QColor(0xff,0xff,0xff,0x0f)); // painter->drawRoundedRect(option->rect,6,6); } else { // painter->setRenderHint(QPainter::Antialiasing,true); // painter->setPen(Qt::NoPen); // painter->setBrush(QColor(0xff,0xff,0xff,0x1f)); // painter->drawRoundedRect(option->rect.adjusted(2,2,-2,-2),6,6); } } painter->restore(); return; } } case PE_PanelButtonCommand: { if (const QStyleOptionButton *button = qstyleoption_cast(option)) { painter->save(); if (option->state & State_MouseOver) { if (option->state & State_Sunken) { // painter->setRenderHint(QPainter::Antialiasing,true); // painter->setPen(Qt::NoPen); // painter->setBrush(QColor(0xff,0xff,0xff,0x0f)); // painter->drawRoundedRect(button->rect,6,6); } else { // painter->setRenderHint(QPainter::Antialiasing,true); // painter->setPen(Qt::NoPen); // painter->setBrush(QColor(0xff,0xff,0xff,0x1f)); // painter->drawRoundedRect(button->rect.adjusted(2,2,-2,-2),6,6); } } painter->restore(); return; } break; } break; } return QProxyStyle::drawPrimitive(element, option, painter, widget); } QPixmap CustomStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const { return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option); } QStyle::SubControl CustomStyle::hitTestComplexControl( QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const { return QProxyStyle::hitTestComplexControl(control, option, position, widget); } QRect CustomStyle::itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const { return QProxyStyle::itemPixmapRect(rectangle, alignment, pixmap); } QRect CustomStyle::itemTextRect( const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const { return QProxyStyle::itemTextRect(metrics, rectangle, alignment, enabled, text); } // int CustomStyle::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const { switch (metric) { case PM_ToolBarIconSize: { return (int)48 * qApp->devicePixelRatio(); } default: break; } return QProxyStyle::pixelMetric(metric, option, widget); } /*使悬浮点击等样式生效*/ void CustomStyle::polish(QWidget *widget) { widget->setAttribute(Qt::WA_Hover); return QProxyStyle::polish(widget); } void CustomStyle::polish(QApplication *application) { return QProxyStyle::polish(application); } // void CustomStyle::polish(QPalette &palette) { // return QProxyStyle::polish(palette); // QProxyStyle::polish(palette); // palette.setBrush(QPalette::Foreground, Qt::black); QColor lightBlue(200, 0, 0); palette.setBrush(QPalette::Highlight, lightBlue); } void CustomStyle::unpolish(QWidget *widget) { return QProxyStyle::unpolish(widget); } void CustomStyle::unpolish(QApplication *application) { return QProxyStyle::unpolish(application); } QSize CustomStyle::sizeFromContents( QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const { return QProxyStyle::sizeFromContents(type, option, contentsSize, widget); } QIcon CustomStyle::standardIcon( QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const { return QProxyStyle::standardIcon(standardIcon, option, widget); } QPalette CustomStyle::standardPalette() const { return QProxyStyle::standardPalette(); } //如果需要背景透明也许需要用到这个函数 int CustomStyle::styleHint( QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const { switch (hint) { /// 让ScrollView viewport的绘制区域包含scrollbar和corner widget /// 这个例子中没有什么作用,如果我们需要绘制一个背景透明的滚动条 /// 这个style hint对我们的意义应该很大,因为我们希望视图能够帮助 /// 我们填充滚动条的背景区域,否则当背景透明时底下会出现明显的分割 case SH_ScrollView_FrameOnlyAroundContents: { return false; } default: break; } return QProxyStyle::styleHint(hint, option, widget, returnData); } QRect CustomStyle::subControlRect( QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget) const { return QProxyStyle::subControlRect(control, option, subControl, widget); } QRect CustomStyle::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const { return QProxyStyle::subElementRect(element, option, widget); } ukui-power-manager/ukui-power-manager-tray/translations/0000775000175000017500000000000015167661430022445 5ustar fengfengukui-power-manager/ukui-power-manager-tray/translations/ukui-power-manager-tray_zh_CN.ts0000664000175000017500000002450515167661430030600 0ustar fengfeng PowerTray SetPower 设置电源和睡眠 No battery detected 未检测到电池 Fully Charged (100%) 已充满 (100%) %1% available (plugged in) %1% 可用 (已接通电源) %1% remaining %1% 可用 %1 min to fully charge (%2%) 剩余 %1 分钟充满 (%2%) %1 hr %2 min to fully charge (%3%) 剩余 %1 小时 %2 分钟充满 (%3%) %1 min (%2%) remaining 剩余 %1 分钟 (%2%) %1 hr %2 min (%3%) remaining 剩余 %1 小时 %2 分钟 (%3%) powerwindow Charging 正在充电 Discharging 正在放电 Fully Charged 已充满 Endurance 最佳能效 Performance 最佳性能 PowerSettings 电源设置 PowerMode 电源模式 BatteryMode 电池模式 No Battery detected 未检测到电池 %1 minutes until fully charged %1 分钟后 电池将充满 %1 hour %2 minute until fully charged %1 小时 %2 分钟后 电池将充满 %1 hour until fully charged %1 小时后 电池将充满 %1 hour %2 minutes until fully charged %1 小时 %2 分钟后 电池将充满 %1 hours %2 minute until fully charged %1 小时 %2 分钟后 电池将充满 %1 hours until fully charged %1 小时后 电池将充满 %1 hours %2 minutes until fully charged %1 小时 %2 分钟后 电池将充满 %1 minutes remaining 剩余 %1 分钟 %1 hour %2 minute remaining 剩余 %1 小时 %2 分钟 %1 hour remaining 剩余 %1 小时 %1 hour %2 minutes remaining 剩余 %1 小时 %2 分钟 %1 hours %2 minute remaining 剩余 %1 小时 %2 分钟 %1 hours remaining 剩余 %1 小时 %1 hours %2 minutes remaining 剩余 %1 小时 %2 分钟 Better endurance 更好续航 Better performance 更好性能 Best performance 最佳性能 Not Charging 未充电 ukui-power-manager/ukui-power-manager-tray/translations/ukui-power-manager-tray_mn_MN.ts0000664000175000017500000003056215167661430030603 0ustar fengfeng PowerTray SetPower ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠭᠡᠭᠴᠢ ᠪᠠ ᠤᠨᠲᠠᠭ᠎ᠠ ᠲᠣᠬᠢᠷᠠᠭᠤᠯᠤᠨ᠎ᠠ ᠃ No battery detected Fully Charged (100%) ᠨᠢᠭᠡᠨᠲᠡ ᠳᠦᠭᠦᠷᠴᠡᠢ ( 100% ) %1% available (plugged in) %1% ᠶᠢ ᠬᠡᠷᠡᠭ᠍ᠯᠡᠵᠦ ᠪᠣᠯᠬᠤ ( ᠨᠢᠭᠡᠨᠲᠡ ᠬᠠᠳᠬᠤᠨ ᠣᠷᠣᠭᠤᠯᠤᠭᠰᠠᠨ ) %1% remaining %1% ᠶᠢ ᠬᠡᠷᠡᠭᠯᠡᠵᠦ ᠪᠣᠯᠤᠨ᠎ᠠ᠃ %1 min to fully charge (%2%) %1 ᠮᠢᠨᠦᠢᠲ᠋ ᠲᠦ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠨᠡᠮᠡᠵᠦ ᠳᠦᠭᠦᠷᠴᠡᠢ (%2%) %1 hr %2 min to fully charge (%3%) %1 ᠴᠠᠭ %2 ᠮᠢᠨᠦᠢᠲ᠋ ᠲᠦ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠨᠡᠮᠡᠵᠦ ᠳᠦᠭᠦᠷᠴᠡᠢ (%3%) %1 min (%2%) remaining ᠦᠯᠡᠳᠡᠭᠰᠡᠨ ᠨᠢ %1 ᠮᠢᠨᠦᠢᠲ᠋ (%2%) %1 hr %2 min (%3%) remaining %1 ᠴᠠᠭ %2 ᠮᠢᠨᠦ᠋ᠲ (%3%) ᠦᠯᠡᠳᠡᠭᠰᠡᠨ᠃ powerwindow Charging ᠶᠠᠭ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠨᠡᠮᠡᠵᠦ ᠪᠠᠢ᠌ᠨ᠎ᠠ ᠃ Discharging ᠶᠠᠭ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠭᠠᠷᠭᠠᠵᠤ ᠪᠠᠢ᠌ᠨ᠎ᠠ ᠃ Fully Charged ᠨᠢᠭᠡᠨᠲᠡ ᠳᠦᠭᠦᠷᠡᠩ ᠪᠣᠯᠵᠠᠢ ᠃ Endurance ᠬᠠᠮᠤᠭ ᠤᠨ ᠰᠠᠢ᠌ᠨ ᠦᠢᠯᠡᠳᠦᠯ ᠲᠡᠢ ᠃ Performance ᠬᠠᠮᠤᠭ ᠰᠠᠢ᠌ᠨ ᠴᠢᠳᠠᠪᠬᠢ ᠃ PowerSettings ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠭᠡᠭᠴᠢ ᠶᠢᠨ ᠪᠠᠶᠢᠷᠢᠯᠠᠭᠤᠯᠤᠯᠲᠠ᠃ PowerMode ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠭᠡᠭᠴᠢ ᠶᠢᠨ ᠵᠠᠭᠪᠤᠷ ᠃ BatteryMode ᠳ᠋ᠢᠶᠠᠨ ᠢ ᠶᠢᠨ ᠵᠠᠭᠪᠤᠷ ᠃ No Battery detected %1 minutes until fully charged %1 ᠮᠢᠨᠦᠢᠲ᠋ ᠃ ᠳ᠋ᠢᠶᠠᠨ ᠢ ᠳᠦᠭᠦᠷᠡᠩ ᠪᠣᠯᠣᠨ᠎ᠠ ᠃ %1 hour %2 minute until fully charged %1 ᠴᠠᠭ %2 ᠮᠢᠨᠦᠢᠲ᠋ ᠃ ᠳ᠋ᠢᠶᠠᠨ ᠢ ᠳᠦᠭᠦᠷᠡᠩ ᠪᠣᠯᠣᠨ᠎ᠠ ᠃ %1 hour until fully charged %1 ᠴᠠᠭ᠃ ᠳ᠋ᠢᠶᠠᠨ ᠢ ᠳᠦᠭᠦᠷᠡᠩ ᠪᠣᠯᠣᠨ᠎ᠠ ᠃ %1 hour %2 minutes until fully charged %1 ᠴᠠᠭ %2 ᠮᠢᠨᠦᠢᠲ᠋ ᠃ ᠳ᠋ᠢᠶᠠᠨ ᠢ ᠳᠦᠭᠦᠷᠡᠩ ᠪᠣᠯᠣᠨ᠎ᠠ ᠃ %1 hours %2 minute until fully charged %1 ᠴᠠᠭ %2 ᠮᠢᠨᠦᠢᠲ᠋ ᠃ ᠳ᠋ᠢᠶᠠᠨ ᠢ ᠳᠦᠭᠦᠷᠡᠩ ᠪᠣᠯᠣᠨ᠎ᠠ ᠃ %1 hours until fully charged %1 ᠴᠠᠭ᠃ ᠳ᠋ᠢᠶᠠᠨ ᠢ ᠳᠦᠭᠦᠷᠡᠩ ᠪᠣᠯᠣᠨ᠎ᠠ ᠃ %1 hours %2 minutes until fully charged %1 ᠴᠠᠭ %2 ᠮᠢᠨᠦᠢᠲ᠋ ᠃ ᠳ᠋ᠢᠶᠠᠨ ᠢ ᠳᠦᠭᠦᠷᠡᠩ ᠪᠣᠯᠣᠨ᠎ᠠ ᠃ %1 minutes remaining ᠦᠯᠡᠳᠡᠭᠰᠡᠨ᠃ %1 ᠮᠢᠨᠦᠢᠲ᠋ ᠃ %1 hour %2 minute remaining ᠦᠯᠡᠳᠡᠭᠰᠡᠨ᠃ %1 ᠴᠠᠭ ᠤᠨ ᠬᠣᠭᠣᠴᠠᠭ᠎ᠠ %2 ᠮᠢᠨᠦᠢᠲ᠋ ᠃ %1 hour remaining %1 ᠴᠠᠭ᠃ %1 ᠴᠠᠭ᠃ %1 hour %2 minutes remaining ᠦᠯᠡᠳᠡᠭᠰᠡᠨ᠃ %1 ᠴᠠᠭ ᠤᠨ ᠬᠣᠭᠣᠴᠠᠭ᠎ᠠ %2 ᠮᠢᠨᠦᠢᠲ᠋ ᠃ %1 hours %2 minute remaining ᠦᠯᠡᠳᠡᠭᠰᠡᠨ᠃ %1 ᠴᠠᠭ ᠤᠨ ᠬᠣᠭᠣᠴᠠᠭ᠎ᠠ %2 ᠮᠢᠨᠦᠢᠲ᠋ ᠃ %1 hours remaining ᠦᠯᠡᠳᠡᠭᠰᠡᠨ᠃ %1 ᠴᠠᠭ᠃ %1 hours %2 minutes remaining ᠦᠯᠡᠳᠡᠭᠰᠡᠨ᠃ %1 ᠴᠠᠭ ᠤᠨ ᠬᠣᠭᠣᠴᠠᠭ᠎ᠠ %2 ᠮᠢᠨᠦᠢᠲ᠋ ᠃ Better endurance ᠨᠡᠩ ᠰᠠᠶᠢᠨ ᠦᠷᠭᠦᠯᠵᠢᠯᠡᠨ ᠠᠶᠠᠯᠠᠨ᠎ᠠ ᠃ Better performance ᠨᠡᠩ ᠰᠠᠶᠢᠨ ᠴᠢᠳᠠᠪᠬᠢ ᠃ Best performance ᠬᠠᠮᠤᠭ ᠰᠠᠢ᠌ᠨ ᠴᠢᠳᠠᠪᠬᠢ ᠃ Not Charging цэнэггүй ukui-power-manager/ukui-power-manager-tray/translations/ukui-power-manager-tray_mn.ts0000664000175000017500000002350015167661430030203 0ustar fengfeng PowerTray SetPower No battery detected Батерей олдсонгүй Fully Charged (100%) %1% available (plugged in) %1% remaining %1 min to fully charge (%2%) %1 hr %2 min to fully charge (%3%) %1 min (%2%) remaining %1 hr %2 min (%3%) remaining powerwindow Charging Discharging Fully Charged Endurance Performance ᠴᠢᠳᠠᠪᠬᠢ ᠵᠢᠨ ᠵᠠᠭᠪᠤᠷ PowerSettings PowerMode BatteryMode No Battery detected Батерей олдсонгүй %1 minutes until fully charged %1 hour %2 minute until fully charged %1 hour until fully charged %1 hour %2 minutes until fully charged %1 hours %2 minute until fully charged %1 hours until fully charged %1 hours %2 minutes until fully charged %1 minutes remaining %1 hour %2 minute remaining %1 hour remaining %1 hour %2 minutes remaining %1 hours %2 minute remaining %1 hours remaining %1 hours %2 minutes remaining Not Charging ukui-power-manager/ukui-power-manager-tray/translations/ukui-power-manager-tray_bo_CN.ts0000664000175000017500000003050615167661430030555 0ustar fengfeng PowerTray SetPower བཀོད་སྒྲིག། No battery detected གློག་རྫས་རྙེད་མ་སོང་། Fully Charged (100%) གློག་གསོག་ཚད་ཚང་མ་(100%) %1% available (plugged in) %1% བཀོལ་སྤྱོད་བྱས་ཆོག (ནང་དུ་བཅུག་པ།) %1% remaining %1% དེ་བྱིངས་ཚང་མ་ལྷག %1 min to fully charge (%2%) སྐར་མ་ %1 ཡི་རིང་ལ་གློག་གསོག་དགོས། (%2%) %1 hr %2 min to fully charge (%3%) ཆུ་ཚོད་ %1 དང་སྐར་མ་ %2 ཡི་རིང་ལ་གློག་གསོག་དགོས། (%3%) %1 min (%2%) remaining དང་སྐར་མ་ %1 ལྷག་ཡོད། (%2%) %1 hr %2 min (%3%) remaining སྐར་མ་ %1 དང་སྐར་མ་ %2 ལྷག་ཡོད། (%3%) powerwindow Charging གློག་གསོག་པའི་ནང། Endurance གློག་གསོག་པའི་ནང། Performance ནུས་པ། PowerSettings བཀོད་སྒྲིག། PowerMode གློག་ཁུངས་དཔེ་དབྱིབས། BatteryMode གློག་གཡིས་དཔེ་དབྱིབས། No Battery detected གློག་རྫས་རྙེད་མ་སོང་། Discharging གློག་འཁྱུག་པ། %1 minutes until fully charged སྐར་མ་%1 ཕྱོགས་ཡོངས་ནས་གློག་གསོག་རག་བར་ %1 hour %2 minute until fully charged ཆུ་ཚོད་%1དང་སྐར་མ་%2 ཕྱོགས་ཡོངས་ནས་གློག་གསོག་རག་བར་ %1 hour until fully charged ཆུ་ཚོད་%1 ཕྱོགས་ཡོངས་ནས་གློག་གསོག་རག་བར་ %1 hour %2 minutes until fully charged ཆུ་ཚོད་%1དང་སྐར་མ་%2 ཕྱོགས་ཡོངས་ནས་གློག་གསོག་རག་བར་ %1 hours %2 minute until fully charged ཆུ་ཚོད་%1དང་སྐར་མ་%2 ཕྱོགས་ཡོངས་ནས་གློག་གསོག་རག་བར་ %1 hours until fully charged ཆུ་ཚོད་%1 ཕྱོགས་ཡོངས་ནས་གློག་གསོག་རག་བར་ %1 hours %2 minutes until fully charged ཆུ་ཚོད་%1དང་སྐར་མ་%2 ཕྱོགས་ཡོངས་ནས་གློག་གསོག་རག་བར་ %1 minutes remaining དེ་བྱིངས་ཚང་མ་ལྷག སྐར་མ་%1 %1 hour %2 minute remaining དེ་བྱིངས་ཚང་མ་ལྷག ཆུ་ཚོད་%1དང་སྐར་མ་%2 %1 hour remaining དེ་བྱིངས་ཚང་མ་ལྷག ཆུ་ཚོད་%1 %1 hour %2 minutes remaining དེ་བྱིངས་ཚང་མ་ལྷག ཆུ་ཚོད་%1དང་སྐར་མ་%2 %1 hours %2 minute remaining དེ་བྱིངས་ཚང་མ་ལྷག ཆུ་ཚོད་%1དང་སྐར་མ་%2 %1 hours remaining དེ་བྱིངས་ཚང་མ་ལྷག ཆུ་ཚོད་%1 %1 hours %2 minutes remaining དེ་བྱིངས་ཚང་མ་ལྷག ཆུ་ཚོད་%1དང་སྐར་མ་%2 Fully Charged གློག་གསོག་ཚད་ཚང་མ་ Better endurance གློག་སྨན། Better performance དོ་མཉམ། Best performance ཆེས་ལེགས་པའི་ནུས་པ། Not Charging ཆ་འཕྲིན་མ་བྱུང་།‌ ukui-power-manager/ukui-power-manager-tray/translations/ukui-power-manager-tray_kk.ts0000664000175000017500000001711615167661430030204 0ustar fengfeng PowerTray SetPower No battery detected Fully Charged (100%) %1% available (plugged in) %1% remaining %1 min to fully charge (%2%) %1 hr %2 min to fully charge (%3%) %1 min (%2%) remaining %1 hr %2 min (%3%) remaining powerwindow Charging Discharging Fully Charged Endurance Performance PowerSettings PowerMode BatteryMode No Battery detected %1 minutes until fully charged %1 hour %2 minute until fully charged %1 hour until fully charged %1 hour %2 minutes until fully charged %1 hours %2 minute until fully charged %1 hours until fully charged %1 hours %2 minutes until fully charged %1 minutes remaining %1 hour %2 minute remaining %1 hour remaining %1 hour %2 minutes remaining %1 hours %2 minute remaining %1 hours remaining %1 hours %2 minutes remaining Better endurance 更好续航 Better performance 更好性能 Best performance 最佳性能 ukui-power-manager/ukui-power-manager-tray/translations/ukui-power-manager-tray_tr.ts0000664000175000017500000002432315167661430030222 0ustar fengfeng PowerTray SetPower 设置电源和睡眠 No battery detected Pil algılanmadı Fully Charged (100%) 已充满 (100%) %1% available (plugged in) %1% 可用 (已接通电源) %1% remaining %1% 可用 %1 min to fully charge (%2%) 剩余 %1 分钟充满 (%2%) %1 hr %2 min to fully charge (%3%) 剩余 %1 小时 %2 分钟充满 (%3%) %1 min (%2%) remaining 剩余 %1 分钟 (%2%) %1 hr %2 min (%3%) remaining 剩余 %1 小时 %2 分钟 (%3%) powerwindow Charging 正在充电 Discharging 正在放电 Fully Charged 已充满 Endurance 续航 Performance 性能 PowerSettings 电源设置 PowerMode 电源模式 BatteryMode 电池模式 No Battery detected Pil algılanmadı %1 minutes until fully charged %1 分钟后 电池将充满 %1 hour %2 minute until fully charged %1 hour until fully charged %1 hour %2 minutes until fully charged %1 hours %2 minute until fully charged %1 hours until fully charged %1 hours %2 minutes until fully charged %1 小时 %2 分钟后 电池将充满 %1 minutes remaining 剩余 %1 分钟 %1 hour %2 minute remaining %1 hour remaining %1 hour %2 minutes remaining %1 hours %2 minute remaining %1 hours remaining %1 hours %2 minutes remaining 剩余 %1 小时 %2 分钟 Better endurance 更好续航 Better performance 更好性能 Best performance 最佳性能 Not Charging 未充电 ukui-power-manager/ukui-power-manager-tray/translations/ukui-power-manager-tray_vi.ts0000664000175000017500000002225415167661430030214 0ustar fengfeng NotificationDialog The system will %1 in 60 seconds as the battery is about to run out. Hệ thống sẽ %1 trong 60 giây khi pin sắp hết. I know Tôi biết The system will %1 in %2 seconds as the battery is about to run out. Hệ thống sẽ%1 trong%2 giây khi pin sắp hết. shutdown Shutdown hibernate Ngủ đông suspend Dừng lại PowerTray SetPower Công suất đặt fully charged (100%) Đã sạc đầy (100%) %1% available (plugged in) %1% khả dụng (cắm vào) %1% remaining %1% khả dụng %1 min to fully charge (%2%) Còn %1 phút để sạc đầy (%2%) %1 hr %2 min to fully charge (%3%) %1 giờ%2 phút để sạc đầy (%3%) %1 min (%2%) remaining Còn %1 phút (%2%) %1 hr %2 min (%3%) remaining %1 giờ %2 phút (%3%) còn lại powerwindow Charging Đang sạc Discharging Xả fully charged Đã sạc đầy Endurance Độ bền Performance Chế độ hiệu suất PowerSettings Cài đặt nguồn điện PowerMode Chế độ nguồn điện BatteryMode Chế độ pin %1 minutes until fully charged Pin sẽ đầy sau %1 phút %1 hour %2 minute until fully charged Pin sẽ đầy sau %1 giờ %2 phút %1 hour until fully charged Pin sẽ đầy sau %1 giờ %1 hour %2 minutes until fully charged %1 giờ%2 phút cho đến khi được sạc đầy %1 hours %2 minute until fully charged %1 giờ%2 phút cho đến khi được sạc đầy %1 hours until fully charged Pin sẽ đầy sau %1 giờ %1 hours %2 minutes until fully charged Pin sẽ đầy sau %1 giờ %2 phút %1 minutes remaining %1 phút Còn lại %1 hour %2 minute remaining %1 giờ%2 phút Còn lại %1 hour remaining Còn %1 giờ %1 hour %2 minutes remaining %1 giờ%2 phút Còn lại %1 hours %2 minute remaining Còn %1 giờ %2 phút %1 hours remaining %1 giờ Còn lại %1 hours %2 minutes remaining %1 giờ%2 phút Còn lại Better endurance Thời gian sử dùng pin dài hơn Better performance Hiệu năng tốt hơn Best performance Hiệu suất tốt nhất ukui-power-manager/ukui-power-manager-tray/translations/ukui-power-manager-tray_zh_HK.ts0000664000175000017500000002450215167661430030577 0ustar fengfeng PowerTray SetPower 設置電源和睡眠 No battery detected 未檢測到電池 Fully Charged (100%) 已充滿 (100%) %1% available (plugged in) %1% 可用 (已接通電源) %1% remaining %1% 可用 %1 min to fully charge (%2%) 剩餘 %1 分鐘充滿 (%2%) %1 hr %2 min to fully charge (%3%) 剩餘 %1 小時 %2 分鐘充滿 (%3%) %1 min (%2%) remaining 剩餘 %1 分鐘 (%2%) %1 hr %2 min (%3%) remaining 剩餘 %1 小時 %2 分鐘 (%3%) powerwindow Charging 正在充電 Discharging 正在放電 Fully Charged 已充滿 Endurance 最佳能效 Performance 最佳性能 PowerSettings 電源設置 PowerMode 電源模式 BatteryMode 電池模式 No Battery detected 未檢測到電池 %1 minutes until fully charged %1 分鐘後 電池將充滿 %1 hour %2 minute until fully charged %1 小時 %2 分鐘後 電池將充滿 %1 hour until fully charged %1 小時後 電池將充滿 %1 hour %2 minutes until fully charged %1 小時 %2 分鐘後 電池將充滿 %1 hours %2 minute until fully charged %1 小時 %2 分鐘後 電池將充滿 %1 hours until fully charged %1 小時後 電池將充滿 %1 hours %2 minutes until fully charged %1 小時 %2 分鐘後 電池將充滿 %1 minutes remaining 剩餘 %1 分鐘 %1 hour %2 minute remaining 剩餘 %1 小時 %2 分鐘 %1 hour remaining 剩餘 %1 小時 %1 hour %2 minutes remaining 剩餘 %1 小時 %2 分鐘 %1 hours %2 minute remaining 剩餘 %1 小時 %2 分鐘 %1 hours remaining 剩餘 %1 小時 %1 hours %2 minutes remaining 剩餘 %1 小時 %2 分鐘 Better endurance 更好續航 Better performance 更好性能 Best performance 最佳性能 Not Charging 未充電 ukui-power-manager/ukui-power-manager-tray/translations/ukui-power-manager-tray_ms.ts0000664000175000017500000001711615167661430030216 0ustar fengfeng PowerTray SetPower No battery detected Fully Charged (100%) %1% available (plugged in) %1% remaining %1 min to fully charge (%2%) %1 hr %2 min to fully charge (%3%) %1 min (%2%) remaining %1 hr %2 min (%3%) remaining powerwindow Charging Discharging Fully Charged Endurance Performance PowerSettings PowerMode BatteryMode No Battery detected %1 minutes until fully charged %1 hour %2 minute until fully charged %1 hour until fully charged %1 hour %2 minutes until fully charged %1 hours %2 minute until fully charged %1 hours until fully charged %1 hours %2 minutes until fully charged %1 minutes remaining %1 hour %2 minute remaining %1 hour remaining %1 hour %2 minutes remaining %1 hours %2 minute remaining %1 hours remaining %1 hours %2 minutes remaining Better endurance 更好续航 Better performance 更好性能 Best performance 最佳性能 ukui-power-manager/ukui-power-manager-tray/translations/ukui-power-manager-tray_ar.ts0000664000175000017500000002155015167661430030176 0ustar fengfeng NotificationDialog The system will %1 in 60 seconds as the battery is about to run out. I know The system will %1 in %2 seconds as the battery is about to run out. shutdown hibernate suspend PowerTray SetPower fully charged (100%) %1% available (plugged in) %1% remaining %1 min to fully charge (%2%) %1 hr %2 min to fully charge (%3%) %1 min (%2%) remaining %1 hr %2 min (%3%) remaining powerwindow Charging Discharging fully charged Endurance Performance PowerSettings PowerMode BatteryMode %1 minutes until fully charged %1 hour %2 minute until fully charged %1 hour until fully charged %1 hour %2 minutes until fully charged %1 hours %2 minute until fully charged %1 hours until fully charged %1 hours %2 minutes until fully charged %1 minutes remaining %1 hour %2 minute remaining %1 hour remaining %1 hour %2 minutes remaining %1 hours %2 minute remaining %1 hours remaining %1 hours %2 minutes remaining Better endurance Better performance Best performance ukui-power-manager/ukui-power-manager-tray/resources/0000775000175000017500000000000015167661415021741 5ustar fengfengukui-power-manager/ukui-power-manager-tray/resources/ukui-power-manager-tray.desktop0000664000175000017500000000064315167661415030033 0ustar fengfeng[Desktop Entry] _Name=Power Manager Tray Name[zh_CN]=电源管理程序 _Comment=Power management tray Icon=ukui-power-manager Exec=ukui-power-manager-tray Terminal=false Type=Application NoDisplay=true Categories= OnlyShowIn=UKUI; X-UKUI-Bugzilla-Bugzilla=UKUI X-UKUI-Bugzilla-Product=ukui-power-manager-tray X-UKUI-Bugzilla-Component=ukui-power-manager-tray X-UKUI-Bugzilla-Version=@VERSION@ X-UKUI-AutoRestart=true ukui-power-manager/ukui-power-manager-tray/upower-dbus/0000775000175000017500000000000015167661430022200 5ustar fengfengukui-power-manager/ukui-power-manager-tray/upower-dbus/upowerlinepowerdbus.cpp0000664000175000017500000000702415167661430027033 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upowerlinepowerdbus.h" #include #include UpowerLinePowerDBus::UpowerLinePowerDBus(int linePowerId, const QString &linePowerDBusPath, QObject *parent) : QObject(parent), m_linePowerId(linePowerId) { qDebug() << "linePowerDBusPath :" << linePowerDBusPath; m_DBusInterface = new QDBusInterface("org.freedesktop.UPower", linePowerDBusPath, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus(), this); QDBusConnection::systemBus().connect("org.freedesktop.UPower", linePowerDBusPath, "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(dealLinePowerPropertiesMessage(QDBusMessage))); QDBusReply reply = m_DBusInterface->call("Get", "org.freedesktop.UPower.Device", "Online"); if (reply.isValid()) { m_acOnlineState = reply.value().toBool(); } else { m_acOnlineState = false; } QDBusReply pathReply = m_DBusInterface->call("Get", "org.freedesktop.UPower.Device", "NativePath"); if (pathReply.isValid()) { m_nativePath = pathReply.value().toString(); qDebug() << "NativePath = " << m_nativePath; } else { qWarning() << "get native path error!"; } } UpowerLinePowerDBus::~UpowerLinePowerDBus() {} void UpowerLinePowerDBus::dealLinePowerPropertiesMessage(QDBusMessage msg) { const QDBusArgument &dbusArgs = msg.arguments().at(1).value(); QMap map; dbusArgs >> map; qDebug() << "line power id:" << m_linePowerId; if (map.contains("Online")) { bool acOnlineState = map.value(QString("Online")).toBool(); if (m_acOnlineState != acOnlineState) { m_acOnlineState = acOnlineState; Q_EMIT acOnlineStateChanged(m_linePowerId, m_acOnlineState); } } } int UpowerLinePowerDBus::getAcOnlineState() { return m_acOnlineState; } bool UpowerLinePowerDBus::getOnLineStateFromSysFile() { QFile file("/sys/class/power_supply/" + m_nativePath + "/online"); // 尝试以只读和文本模式打开文件 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "无法打开文件:" << file.errorString(); return false; } QTextStream in(&file); QString content = in.readAll().trimmed(); // 读取全部内容并去除首尾空白字符 file.close(); qDebug() << QString ("/sys/class/power_supply/" + m_nativePath + "/online is ") << content; if (content == "1") { return true; } return false; } ukui-power-manager/ukui-power-manager-tray/upower-dbus/upowerbatterydbus.h0000664000175000017500000000355415167661430026152 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPOWERBATTERYDBUS_H #define UPOWERBATTERYDBUS_H #include #include #include typedef enum { battery_state_unknown = 0, battery_state_charging, battery_state_discharging, battery_state_empty, battery_state_fully, battery_state_pending_charge, battery_state_pending_discharge, battery_state_last } BatteryState; class UpowerBatteryDBus : public QObject { Q_OBJECT public: explicit UpowerBatteryDBus(int batteryId, const QString &batteryDBusPath, QObject *parent = nullptr); ~UpowerBatteryDBus(); private: void initBatteryInfo(); int m_batteryId; QString m_batteryDBusPath; QDBusInterface *m_DBusInterface; bool m_batteryPresent; int m_batteryState; double m_percentage; qlonglong m_timeToFull; qlonglong m_timeToEmpty; Q_SIGNALS: void batteryInfoChanged(int, QStringList); private Q_SLOTS: void dealBatteryPropertiesMessage(QDBusMessage); public: bool batteryIsPresent(); int getBatteryState(); double getBatteryPercentage(); qlonglong getTimeToFull(); qlonglong getTimeToEmpty(); void refreshBatteryInfo(); }; #endif // UPOWERBATTERYDBUS_H ukui-power-manager/ukui-power-manager-tray/upower-dbus/upowerdbus.h0000664000175000017500000000411215167661430024546 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPOWERDBUS_H #define UPOWERDBUS_H #include #include #include enum up_device_type { up_device_type_unknown = 0, up_device_type_line_power, up_device_type_battery, up_device_type_ups, up_device_type_monitor, up_device_type_mouse, up_device_type_keyboard, up_device_type_pda, up_device_type_phone, up_device_type_media_player, up_device_type_tablet, up_device_type_computer, up_device_type_max }; class UPowerDBus : public QObject { Q_OBJECT public: explicit UPowerDBus(QObject *parent = nullptr); ~UPowerDBus(); private: void initDeviceInfo(); void dealLidClosedMessage(bool); void dealBatteryOnlineMessage(bool); QDBusInterface *m_DBusInterface; bool m_hasLid; bool m_lidIsClosed; bool m_batteryOnline; QString m_upowerDaemonVersion; QStringList m_batteryPathList; QStringList m_linePowerPathList; private Q_SLOTS: void dealUPowerDBusMessage(QDBusMessage); Q_SIGNALS: void lidStateChanged(bool); void batteryOnlineStateChanged(bool); public: bool hasLid(); bool getLidClosedState(); bool getBatteryOnlineState(); QString getUpowerDaemonVersion(); QStringList getBatteryPathList(); QStringList getLinePowerPathList(); void refreshDevicePathLists(); int getDeviceType(const QString &); }; #endif // UPOWERDBUS_H ukui-power-manager/ukui-power-manager-tray/upower-dbus/upowerdbus.cpp0000664000175000017500000001270715167661430025112 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upowerdbus.h" UPowerDBus::UPowerDBus(QObject *parent) : QObject(parent) { m_DBusInterface = new QDBusInterface("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.DBus.Properties", QDBusConnection::systemBus()); QDBusConnection::systemBus().connect("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(dealUPowerDBusMessage(QDBusMessage))); refreshDevicePathLists(); initDeviceInfo(); } UPowerDBus::~UPowerDBus() { delete m_DBusInterface; } void UPowerDBus::refreshDevicePathLists() { m_batteryPathList.clear(); QDBusInterface dBusInterface("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.UPower", QDBusConnection::systemBus()); QDBusReply> reply = dBusInterface.call("EnumerateDevices"); if (dBusInterface.isValid()) { for (QDBusObjectPath dBusObjectPath : reply.value()) { int upDeviceType = getDeviceType(dBusObjectPath.path()); qDebug() << "device type:" << upDeviceType; if (up_device_type_line_power == upDeviceType) { m_linePowerPathList << dBusObjectPath.path(); qDebug() << "line_power dBusObjectPath:" << dBusObjectPath.path(); } else if (up_device_type_battery == upDeviceType) { m_batteryPathList << dBusObjectPath.path(); qDebug() << "battery dBusObjectPath:" << dBusObjectPath.path(); } } } } int UPowerDBus::getDeviceType(const QString &dBusPath) { qDebug() << "device dBus object path:" << dBusPath; // upower dbus device path /org/freedesktop/UPower/devices/keyboard_hidpp_battery_0 QString deviceName = dBusPath.split('/').last(); QString deviceType = deviceName.split('_').first(); qInfo() << "device name:" << deviceName << "device type:" << deviceType; if ("keyboard" == deviceType) { return up_device_type_keyboard; } if ("mouse" == deviceType) { return up_device_type_mouse; } QDBusInterface dBusInterface("org.freedesktop.UPower", dBusPath, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus()); QDBusReply reply = dBusInterface.call("Get", "org.freedesktop.UPower.Device", "Type"); if (reply.isValid()) { return reply.value().toInt(); } else { qDebug() << "Get device type failed"; return up_device_type_unknown; } } void UPowerDBus::initDeviceInfo() { QDBusMessage msg = m_DBusInterface->call("GetAll", "org.freedesktop.UPower"); if (msg.type() == QDBusMessage::ReplyMessage) { const QDBusArgument &dbusArgs = msg.arguments().at(0).value(); QMap map; dbusArgs >> map; m_hasLid = map.value(QString("LidIsPresent")).toBool(); m_lidIsClosed = map.value(QString("LidIsClosed")).toBool(); m_batteryOnline = map.value(QString("OnBattery")).toBool(); m_upowerDaemonVersion = map.value(QString("DaemonVersion")).toString(); } } void UPowerDBus::dealLidClosedMessage(bool value) { if (m_lidIsClosed != value) { m_lidIsClosed = value; Q_EMIT lidStateChanged(m_lidIsClosed); } } void UPowerDBus::dealBatteryOnlineMessage(bool value) { if (m_batteryOnline != value) { m_batteryOnline = value; Q_EMIT batteryOnlineStateChanged(m_batteryOnline); } } void UPowerDBus::dealUPowerDBusMessage(QDBusMessage msg) { const QDBusArgument &dbusArgs = msg.arguments().at(1).value(); QMap map; dbusArgs >> map; if (map.contains("LidIsClosed")) { dealLidClosedMessage(map.value(QString("LidIsClosed")).toBool()); } if (map.contains("OnBattery")) { dealBatteryOnlineMessage(map.value(QString("OnBattery")).toBool()); } } bool UPowerDBus::hasLid() { return m_hasLid; } bool UPowerDBus::getLidClosedState() { return m_lidIsClosed; } bool UPowerDBus::getBatteryOnlineState() { return m_batteryOnline; } QString UPowerDBus::getUpowerDaemonVersion() { return m_upowerDaemonVersion; } QStringList UPowerDBus::getBatteryPathList() { return m_batteryPathList; } QStringList UPowerDBus::getLinePowerPathList() { return m_linePowerPathList; } ukui-power-manager/ukui-power-manager-tray/upower-dbus/upowerbatterydbus.cpp0000664000175000017500000001031015167661430026471 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upowerbatterydbus.h" UpowerBatteryDBus::UpowerBatteryDBus(int batteryId, const QString &batteryDBusPath, QObject *parent) : QObject(parent), m_batteryId(batteryId), m_batteryDBusPath(batteryDBusPath) { m_DBusInterface = new QDBusInterface("org.freedesktop.UPower", m_batteryDBusPath, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus(), this); QDBusConnection::systemBus().connect("org.freedesktop.UPower", m_batteryDBusPath, "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(dealBatteryPropertiesMessage(QDBusMessage))); initBatteryInfo(); } UpowerBatteryDBus::~UpowerBatteryDBus() {} void UpowerBatteryDBus::dealBatteryPropertiesMessage(QDBusMessage msg) { const QDBusArgument &dbusArgs = msg.arguments().at(1).value(); QMap map; dbusArgs >> map; QStringList batteryInfoChangedList; if (map.contains("IsPresent")) { m_batteryPresent = map.value(QString("IsPresent")).toBool(); batteryInfoChangedList.append("IsPresent"); } if (map.contains("State")) { m_batteryState = map.value(QString("State")).toInt(); batteryInfoChangedList.append("State"); } if (map.contains("Percentage")) { m_percentage = map.value(QString("Percentage")).toDouble(); batteryInfoChangedList.append("Percentage"); } if (map.contains("TimeToFull")) { m_timeToFull = map.value(QString("TimeToFull")).toLongLong(); batteryInfoChangedList.append("TimeToFull"); } if (map.contains("TimeToEmpty")) { m_timeToEmpty = map.value(QString("TimeToEmpty")).toLongLong(); batteryInfoChangedList.append("TimeToEmpty"); } if (0 != batteryInfoChangedList.size()) { Q_EMIT batteryInfoChanged(m_batteryId, batteryInfoChangedList); } } void UpowerBatteryDBus::initBatteryInfo() { QDBusMessage msg = m_DBusInterface->call("GetAll", "org.freedesktop.UPower.Device"); if (msg.type() == QDBusMessage::ReplyMessage) { const QDBusArgument &dbusArgs = msg.arguments().at(0).value(); QMap map; dbusArgs >> map; m_batteryPresent = map.value(QString("IsPresent")).toBool(); m_batteryState = map.value(QString("State")).toInt(); m_percentage = map.value(QString("Percentage")).toDouble(); m_timeToFull = map.value(QString("TimeToFull")).toLongLong(); m_timeToEmpty = map.value(QString("TimeToEmpty")).toLongLong(); } } bool UpowerBatteryDBus::batteryIsPresent() { return m_batteryPresent; } int UpowerBatteryDBus::getBatteryState() { return m_batteryState; } double UpowerBatteryDBus::getBatteryPercentage() { return m_percentage; } qlonglong UpowerBatteryDBus::getTimeToFull() { return m_timeToFull; } qlonglong UpowerBatteryDBus::getTimeToEmpty() { return m_timeToEmpty; } void UpowerBatteryDBus::refreshBatteryInfo() { QDBusInterface dBusInterface("org.freedesktop.UPower", m_batteryDBusPath, "org.freedesktop.UPower.Device", QDBusConnection::systemBus()); dBusInterface.call("Refresh"); } ukui-power-manager/ukui-power-manager-tray/upower-dbus/upm_upowerdbus.h0000664000175000017500000000446115167661430025436 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPM_UPOWERDBUS_H #define UPM_UPOWERDBUS_H #include #include "upowerdbus.h" #include "upowerbatterydbus.h" #include "upowerlinepowerdbus.h" class UpmUpowerDBus : public QObject { Q_OBJECT public: explicit UpmUpowerDBus(QObject *parent = nullptr); ~UpmUpowerDBus(); static UpmUpowerDBus* self(); void refreshBatteryInfo(); bool getAcOnlineStateFromSysfile(); private: UPowerDBus *m_upowerDBus; QVector m_batteryDBusVector; QVector m_linePowerDBusVector; QString m_batteryIconName; void initializeBatteryObjects(); void clearBatteryObjects(); void rebuildBatteryObjects(); Q_SIGNALS: void lidStateChanged(bool); void batteryOnlineStateChanged(bool); void batteryInfoChanged(int, QStringList); void acOnlineStateChanged(int, bool); void deviceChanged(); private: void dealLidStateChanged(bool); void dealBatteryOnlineStateChanged(bool); void dealBatteryInfoChanged(int, QStringList); void dealAcOnlineStateChanged(int, bool); public Q_SLOTS: bool getLidClosedState(); bool getBatteryOnlineState(); bool hasBattery(); bool batteryIsPresent(int index = 0); int getBatteryState(int index = 0); int getBatteryNum(); int getLinePowerNum(); double getBatteryPercentage(); qlonglong getTimeToFull(int index = 0); qlonglong getTimeToEmpty(int index = 0); QString getBatteryIconName(int index = 0); bool getAcOnlineState(); void onDeviceAdded(QDBusObjectPath); void onDeviceRemoved(QDBusObjectPath); }; #endif // UPM_UPOWERDBUS_H ukui-power-manager/ukui-power-manager-tray/upower-dbus/upowerlinepowerdbus.h0000664000175000017500000000255215167661430026501 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPOWERLINEPOWERDBUS_H #define UPOWERLINEPOWERDBUS_H #include #include #include class UpowerLinePowerDBus : public QObject { Q_OBJECT public: explicit UpowerLinePowerDBus(int linePowerId, const QString &linePowerDBusPath, QObject *parent = nullptr); ~UpowerLinePowerDBus(); bool getOnLineStateFromSysFile(); int getAcOnlineState(); private: int m_linePowerId; QDBusInterface *m_DBusInterface; bool m_acOnlineState; QString m_nativePath = ""; Q_SIGNALS: void acOnlineStateChanged(int, bool); private Q_SLOTS: void dealLinePowerPropertiesMessage(QDBusMessage); }; #endif // UPOWERLINEPOWERDBUS_H ukui-power-manager/ukui-power-manager-tray/upower-dbus/upm_upowerdbus.cpp0000664000175000017500000002015415167661430025766 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "upm_upowerdbus.h" Q_GLOBAL_STATIC(UpmUpowerDBus, s_upowerDBus) UpmUpowerDBus::UpmUpowerDBus(QObject *parent) : QObject(parent) { m_upowerDBus = new UPowerDBus(this); connect(m_upowerDBus, &UPowerDBus::lidStateChanged, this, &UpmUpowerDBus::dealLidStateChanged); connect(m_upowerDBus, &UPowerDBus::batteryOnlineStateChanged, this, &UpmUpowerDBus::dealBatteryOnlineStateChanged); initializeBatteryObjects(); QStringList linePowerPathList = m_upowerDBus->getLinePowerPathList(); for (int index = 0; index < linePowerPathList.size(); ++index) { UpowerLinePowerDBus *upowerLinePowerDBus = new UpowerLinePowerDBus(index, linePowerPathList.at(index), this); connect(upowerLinePowerDBus, &UpowerLinePowerDBus::acOnlineStateChanged, this, &UpmUpowerDBus::dealAcOnlineStateChanged); m_linePowerDBusVector << upowerLinePowerDBus; } qDebug() << "Battery Num:" << m_batteryDBusVector.size(); qDebug() << "line power Num:" << m_linePowerDBusVector.size(); QDBusConnection::systemBus().connect("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.UPower", "DeviceAdded", this, SLOT(onDeviceAdded(QDBusObjectPath))); QDBusConnection::systemBus().connect("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.UPower", "DeviceRemoved", this, SLOT(onDeviceRemoved(QDBusObjectPath))); } UpmUpowerDBus::~UpmUpowerDBus() {} UpmUpowerDBus *UpmUpowerDBus::self() { return s_upowerDBus; } void UpmUpowerDBus::refreshBatteryInfo() { for (int batteryNum = 0; batteryNum < m_batteryDBusVector.size(); ++batteryNum) { m_batteryDBusVector.at(batteryNum)->refreshBatteryInfo(); } } void UpmUpowerDBus::dealLidStateChanged(bool value) { qDebug() << "lid state changed:" << value; Q_EMIT lidStateChanged(value); } void UpmUpowerDBus::dealBatteryOnlineStateChanged(bool value) { Q_EMIT batteryOnlineStateChanged(value); } void UpmUpowerDBus::dealBatteryInfoChanged(int index, QStringList batteryInfoChangedList) { qDebug() << "battery info changed"; Q_EMIT batteryInfoChanged(index, batteryInfoChangedList); } void UpmUpowerDBus::dealAcOnlineStateChanged(int index, bool value) { qDebug() << "ac online changed:" << value; Q_EMIT acOnlineStateChanged(index, value); } bool UpmUpowerDBus::getLidClosedState() { return m_upowerDBus->getLidClosedState(); } bool UpmUpowerDBus::getBatteryOnlineState() { return m_upowerDBus->getBatteryOnlineState(); } bool UpmUpowerDBus::hasBattery() { if (0 == m_batteryDBusVector.size()) { return false; } for (int batteryNum = 0; batteryNum < m_batteryDBusVector.size(); ++batteryNum) { if (true == batteryIsPresent(batteryNum)) { qInfo() << "Equipment has battery"; return true; } } qInfo() << "Equipment no battery"; return false; } bool UpmUpowerDBus::batteryIsPresent(int index) { return m_batteryDBusVector.at(index)->batteryIsPresent(); } int UpmUpowerDBus::getBatteryState(int index) { if (0 == m_batteryDBusVector.size()) { return 0; } return m_batteryDBusVector.at(index)->getBatteryState(); } int UpmUpowerDBus::getBatteryNum() { return m_batteryDBusVector.size(); } int UpmUpowerDBus::getLinePowerNum() { return m_linePowerDBusVector.size(); } double UpmUpowerDBus::getBatteryPercentage() { if (0 == m_batteryDBusVector.size()) { return 0; } double percentage = 0.0; for (int index = 0; index < m_batteryDBusVector.size(); ++index) { percentage += m_batteryDBusVector.at(index)->getBatteryPercentage(); } return percentage / m_batteryDBusVector.size(); } qlonglong UpmUpowerDBus::getTimeToFull(int index) { if (0 == m_batteryDBusVector.size()) { return 0; } return m_batteryDBusVector.at(index)->getTimeToFull(); } qlonglong UpmUpowerDBus::getTimeToEmpty(int index) { if (0 == m_batteryDBusVector.size()) { return 0; } return m_batteryDBusVector.at(index)->getTimeToEmpty(); } QString UpmUpowerDBus::getBatteryIconName(int index) { //处理没有电池的情况 if(!hasBattery()) { if(m_linePowerDBusVector.size() > 0) { if(true == getAcOnlineState()) { qDebug() << "Laptop with no battery detected, showing special battery icon"; return "battery-error-charging-symbolic"; } } } if (0 == m_batteryDBusVector.size() || 0 == m_linePowerDBusVector.size()) { return "battery-level-0-charging-symbolic"; } double percentage = m_batteryDBusVector.at(index)->getBatteryPercentage(); if (true == getAcOnlineState()) { m_batteryIconName = QString("battery-level-%1-charging-symbolic").arg(qRound(percentage / 10.0) * 10); } else { m_batteryIconName = QString("battery-level-%1-symbolic").arg(qRound(percentage / 10.0) * 10); } return m_batteryIconName; } bool UpmUpowerDBus::getAcOnlineState() { if (0 == m_linePowerDBusVector.size()) { return false; } for (int index = 0; index < m_linePowerDBusVector.size(); ++index) { if (true == m_linePowerDBusVector.at(index)->getAcOnlineState() && true == m_linePowerDBusVector.at(index)->getOnLineStateFromSysFile()) { return true; } } return false; } void UpmUpowerDBus::onDeviceAdded(QDBusObjectPath devicePath) { const QString path = devicePath.path(); qInfo() << "Device added:" << path; if(m_upowerDBus->getDeviceType(path) == up_device_type_battery) { rebuildBatteryObjects(); Q_EMIT deviceChanged(); } } void UpmUpowerDBus::onDeviceRemoved(QDBusObjectPath devicePath) { const QString path = devicePath.path(); qInfo() << "Device removed:" << path; if(path.contains("BAT")) { rebuildBatteryObjects(); Q_EMIT deviceChanged(); } } void UpmUpowerDBus::clearBatteryObjects() { for (auto* battery : m_batteryDBusVector) { delete battery; } m_batteryDBusVector.clear(); } void UpmUpowerDBus::initializeBatteryObjects() { QStringList batteryPathList = m_upowerDBus->getBatteryPathList(); for (int index = 0; index < batteryPathList.size(); ++index) { UpowerBatteryDBus *upowerBatteryDBus = new UpowerBatteryDBus(index, batteryPathList.at(index), this); connect(upowerBatteryDBus, &UpowerBatteryDBus::batteryInfoChanged, this, &UpmUpowerDBus::dealBatteryInfoChanged); m_batteryDBusVector << upowerBatteryDBus; } qDebug() << "Initialized" << m_batteryDBusVector.size() << "battery objects"; } void UpmUpowerDBus::rebuildBatteryObjects() { clearBatteryObjects(); m_upowerDBus->refreshDevicePathLists(); initializeBatteryObjects(); } bool UpmUpowerDBus::getAcOnlineStateFromSysfile() { if (0 == m_linePowerDBusVector.size()) { return false; } for (int index = 0; index < m_linePowerDBusVector.size(); ++index) { if (true == m_linePowerDBusVector.at(index)->getOnLineStateFromSysFile()) { return true; } } return false; } ukui-power-manager/ukui-power-manager-tray/kylable.h0000664000175000017500000000253415167661430021524 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef KYLABLE_H #define KYLABLE_H #include #include #include class KyLable : public QLabel { Q_OBJECT public: explicit KyLable(QWidget *parent = nullptr); ~KyLable() = default; protected: void paintEvent(QPaintEvent *event); void enterEvent(QEvent *event); void leaveEvent(QEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); private: QColor m_foregroundColor; QGSettings *m_styleSettings; void setPressColor(); void setHoverColor(); void setNormalColor(); private Q_SLOTS: void onPaletteChanged(); }; #endif // KYLABLE_H ukui-power-manager/ukui-power-manager-tray/main.cpp0000664000175000017500000000373715167661430021366 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "powertray.h" int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); #endif QStringList homePath = QStandardPaths::standardLocations(QStandardPaths::HomeLocation); QString filePath = QString(homePath.at(0) + "/.config/ukui-power-manager-tray%1.lock").arg(getenv("DISPLAY")); int fd = open(filePath.toUtf8().data(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (fd < 0) { exit(1); } if (lockf(fd, F_TLOCK, 0)) { qDebug() << "cant lock single file, ukui-power-manager-tray is already running"; exit(0); } QApplication app(argc, argv); initUkuiLog4qt("ukui-power-manager-tray"); QTranslator translator; if (translator.load(QLocale(), "ukui-power-manager-tray", "_", QM_FILES_INSTALL_PATH)) { app.installTranslator(&translator); } else { qDebug() << "load ukui-power-manager-tray qm file error"; } PowerTray p; return app.exec(); } ukui-power-manager/ukui-power-manager-tray/kylable.cpp0000664000175000017500000000642715167661430022064 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "kylable.h" #include #include #include #include #include #define FOREGROUND_COLOR_NORMAL qApp->palette().text().color() static inline qreal mixQreal(qreal a, qreal b, qreal bias) { return a + (b - a) * bias; } QColor mixColor(const QColor &c1, const QColor &c2, qreal bias) { if (bias <= 0.0) { return c1; } if (bias >= 1.0) { return c2; } if (qIsNaN(bias)) { return c1; } qreal r = mixQreal(c1.redF(), c2.redF(), bias); qreal g = mixQreal(c1.greenF(), c2.greenF(), bias); qreal b = mixQreal(c1.blueF(), c2.blueF(), bias); qreal a = mixQreal(c1.alphaF(), c2.alphaF(), bias); return QColor::fromRgbF(r, g, b, a); } KyLable::KyLable(QWidget *parent) : QLabel(parent), m_styleSettings(new QGSettings(QByteArray("org.ukui.style"))) { connect(qApp, &QApplication::paletteChanged, this, &KyLable::onPaletteChanged); connect(m_styleSettings, &QGSettings::changed, this, [=](QString key) { if ("styleName" == key) { setNormalColor(); this->update(); } }); onPaletteChanged(); } void KyLable::onPaletteChanged() { qDebug() << "palette changed!"; m_foregroundColor = FOREGROUND_COLOR_NORMAL; this->repaint(); } void KyLable::setPressColor() { QColor hightlight = this->palette().color(QPalette::Active, QPalette::Highlight); QColor mix = this->palette().color(QPalette::Active, QPalette::BrightText); m_foregroundColor = mixColor(hightlight, mix, 0.05); } void KyLable::setHoverColor() { QColor hightlight = this->palette().color(QPalette::Active, QPalette::Highlight); QColor mix = this->palette().color(QPalette::Active, QPalette::BrightText); m_foregroundColor = mixColor(hightlight, mix, 0.2); } void KyLable::setNormalColor() { m_foregroundColor = FOREGROUND_COLOR_NORMAL; } void KyLable::paintEvent(QPaintEvent *event) { QPalette pal = this->palette(); pal.setColor(QPalette::WindowText, m_foregroundColor); this->setPalette(pal); return QLabel::paintEvent(event); } void KyLable::enterEvent(QEvent *event) { setHoverColor(); this->update(); } void KyLable::leaveEvent(QEvent *event) { setNormalColor(); this->update(); } void KyLable::mousePressEvent(QMouseEvent *event) { setPressColor(); this->update(); return QLabel::mousePressEvent(event); } void KyLable::mouseReleaseEvent(QMouseEvent *event) { setHoverColor(); this->update(); QProcess::startDetached(QString("ukui-control-center -m Power")); return QLabel::mouseReleaseEvent(event); } ukui-power-manager/ukui-power-manager-tray/powerwindow.cpp0000664000175000017500000005263315167661430023025 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "powerwindow.h" #include "xatom-helper.h" #include #include #include #include #include #include powerwindow::powerwindow(QWidget *parent) : QWidget(parent), m_panelPosition(PanelPosition::panel_bottom) { qDebug() << " power window init start"; initPlatformType(); setWindowProperty(); //设置窗口属性 installEventFilter(this); QVariant value; if (true == UpmGsettings::self()->getGsettingsConfig(GSETTINGS_KEY_SYSTEM_FONT_SIZE, value)) { m_sysFontSize = value.toDouble(); } else { m_sysFontSize = 10; } if (true == UpmGsettings::self()->getGsettingsConfig(GSETTINGS_KEY_POWER_POLICY_AC, value)) { m_powerPolicyAc = value.toInt(); } if (true == UpmGsettings::self()->getGsettingsConfig(GSETTINGS_KEY_POWER_POLICY_BATTERY, value)) { m_powerPolicyBattery = value.toInt(); } initUI(); //初始化UI connect(UpmGsettings::self(), &UpmGsettings::systemFontSizeChanged, this, [=](QVariant value) { m_sysFontSize = value.toDouble(); setPercentageLabelFontsize(); if (true == m_acOnlineChange) { setPowerStateLabelForAcOnlineChanged(); } else { setPowerStateLabelForBatteryInfoChanged(); } }); connect(UpmGsettings::self(), &UpmGsettings::styleNameChanged, this, [=](QVariant value) { m_iconButton->setIcon(QIcon::fromTheme(m_iconName)); }); connect(UpmGsettings::self(), &UpmGsettings::powerPolicyAcChanged, this, [=](QVariant value) { m_powerPolicyAc = value.toInt(); setSliderValue(); }); connect(UpmGsettings::self(), &UpmGsettings::powerPolicyBatteryChanged, this, [=](QVariant value) { m_powerPolicyBattery = value.toInt(); setSliderValue(); }); if (true == UpmGsettings::self()->getGsettingsConfig(GSETTINGS_KEY_TRANSPARENCY_KEY, value)) { m_transparency = value.toDouble(); } this->update(); connect(UpmGsettings::self(), &UpmGsettings::transparencyChanged, this, [=](QVariant value) { m_transparency = value.toDouble(); this->update(); }); //监听屏幕改变的信号 (Qt6 方式) QScreen *primaryScreen = QGuiApplication::primaryScreen(); if (primaryScreen) { connect(primaryScreen, &QScreen::geometryChanged, this, [=]() { QTimer::singleShot(1000, this, [=]() { resetWindowPosition(); }); }); } connect(qApp, &QGuiApplication::screenAdded, this, [=](QScreen *) { resetWindowPosition(); }); connect(qApp, &QGuiApplication::screenRemoved, this, [=](QScreen *) { resetWindowPosition(); }); connect(qApp, &QGuiApplication::primaryScreenChanged, this, [=](QScreen *) { resetWindowPosition(); }); } powerwindow::~powerwindow() {} void powerwindow::setWindowProperty() { //设置任务栏无显示 setWindowOpacity(1); setAttribute(Qt::WA_TranslucentBackground); //设置窗口背景透明 setProperty("useSystemStyleBlur", true); //设置毛玻璃效果 setProperty("useStyleWindowManager", false); m_windowHelper = new UkuiWindowHelper(this); if(false == m_isWayland) { // KWindowEffects::enableBlurBehind(this->winId(), true); // 添加窗管协议 MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); } else { m_windowHelper->setBlurEffect(QRegion(), 0, true); m_windowHelper->removeTitleBar(); m_windowHelper->setSkipTaskBar(true); m_windowHelper->setSkipSwitcher(true); resetWindowPosition(); } } void powerwindow::initUI() { this->setFixedSize(420, 265); m_firstwidget = new QWidget(this); m_topwidget = new QWidget(this); m_lastWidget = new QWidget(this); m_statewidget = new QWidget(this); m_pmainlayout = new QVBoxLayout(this); m_firstlayout = new QHBoxLayout(m_firstwidget); m_toplayout = new QHBoxLayout(m_topwidget); m_lastlayout = new QHBoxLayout(m_lastWidget); m_statelayout = new QHBoxLayout(m_statewidget); m_iconButton = new QPushButton(this); m_iconButton->setFixedSize(QSize(48, 65)); m_iconButton->setIconSize(QSize(30, 30)); m_iconButton->setStyle(new CustomStyle); m_iconButton->setProperty("useIconHighlightEffect", 0x10); m_iconButton->setFlat(true); m_iconButton->setAttribute(Qt::WA_TransparentForMouseEvents); m_percentageLabel = new QLabel(this); setPercentageLabelFontsize(); m_powerStateLabel = new QLabel(this); m_segmentationLine_1 = new Divider(this); m_segmentationLine_2 = new Divider(this); m_StateSlider = new KSlider(this); m_StateSlider->setOrientation(Qt::Orientation::Horizontal); m_StateSlider->setSliderType(KSliderType::SingleSelectSlider); m_StateSlider->setMaximum(2); m_StateSlider->setSingleStep(1); m_StateSlider->setPageStep(1); m_StateSlider->setFixedWidth(372); m_StateSlider->setProperty("needTranslucent", true); m_StateSlider->setTranslucent(true); setSliderValue(); connect(m_StateSlider, &KSlider::valueChanged, this, &powerwindow::sliderValueChanged); m_enduranceIconButtun = new QToolButton(this); m_enduranceIconButtun->setIconSize(QSize(16, 16)); m_enduranceIconButtun->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); m_enduranceIconButtun->setProperty("useIconHighlightEffect", 0x2); m_enduranceIconButtun->setStyle(new CustomStyle); QIcon icon1 = QIcon::fromTheme("ukui-eco-symbolic"); m_enduranceIconButtun->setIcon(icon1); m_enduranceIconButtun->setText(tr("Endurance")); m_performanceIconButtun = new QToolButton(this); m_performanceIconButtun->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); m_performanceIconButtun->setProperty("useIconHighlightEffect", 0x2); m_performanceIconButtun->setStyle(new CustomStyle); QIcon icon2 = QIcon::fromTheme("ukui-performance-symbolic"); m_performanceIconButtun->setIcon(icon2); m_performanceIconButtun->setText(tr("Performance")); //电源设置按钮 m_settingLabel = new KyLable(this); m_settingLabel->setText(tr("PowerSettings")); m_toplabel = new QLabel(this); m_toplabel->setText(tr("PowerMode")); m_toplayout->setContentsMargins(24, 0, 24, 0); m_toplayout->setSpacing(0); m_toplayout->addWidget(m_toplabel); m_toplayout->addItem(new QSpacerItem(10, 2)); //第一行布局 m_firstlayout->setContentsMargins(18, 0, 24, 0); m_firstlayout->setSpacing(0); m_firstlayout->addWidget(m_iconButton, 0, Qt::AlignLeft | Qt::AlignVCenter); m_firstlayout->addWidget(m_percentageLabel, 0, Qt::AlignLeft | Qt::AlignVCenter); m_firstlayout->addStretch(); m_firstlayout->addWidget(m_powerStateLabel, 0, Qt::AlignRight | Qt::AlignVCenter); //滑动条下方标识布局 m_statelayout->setContentsMargins(18, 0, 5, 0); m_statelayout->setSpacing(0); m_statelayout->addWidget(m_enduranceIconButtun, 0, Qt::AlignLeft | Qt::AlignCenter); m_statelayout->addStretch(); m_statelayout->addWidget(m_performanceIconButtun, 0, Qt::AlignRight); //电源设置按钮布局 m_lastlayout->setContentsMargins(24, 0, 24, 0); m_lastlayout->setSpacing(0); m_lastlayout->addWidget(m_settingLabel); m_lastlayout->addStretch(); m_settingLabel->setCursor(Qt::PointingHandCursor); //总体布局 m_pmainlayout->setContentsMargins(0, 0, 0, 0); m_pmainlayout->setSpacing(0); m_pmainlayout->addWidget(m_topwidget); m_pmainlayout->addWidget(m_segmentationLine_1); m_pmainlayout->addSpacing(12); m_pmainlayout->addWidget(m_firstwidget); m_pmainlayout->addSpacing(0); m_pmainlayout->addWidget(m_StateSlider, 0, Qt::AlignCenter); m_pmainlayout->addSpacing(0); m_pmainlayout->addWidget(m_statewidget); m_pmainlayout->addWidget(m_segmentationLine_2); m_pmainlayout->addWidget(m_lastWidget); this->setLayout(m_pmainlayout); } void powerwindow::initPlatformType() { if ("wayland" == qgetenv("XDG_SESSION_TYPE")) { m_isWayland = true; } qDebug() << "Platform is wayland:" << m_isWayland; } void powerwindow::setIconName(QString iconName) { m_iconName = iconName; m_iconButton->setIcon(QIcon::fromTheme(m_iconName)); } void powerwindow::setAcOnlineState(bool acOnlineState) { if (m_acOnlineState == acOnlineState) { return; } m_acOnlineState = acOnlineState; if (true == m_acOnlineState) { m_toplabel->setText(tr("PowerMode")); } else { m_toplabel->setText(tr("BatteryMode")); } setSliderValue(); } void powerwindow::setBatteryState(int iBatteryState) { if (m_batteryState == iBatteryState) { m_batteryStateChanged = false; } else { m_batteryStateChanged = true; m_batteryState = iBatteryState; setSliderValue(); } } void powerwindow::setBatteryPercentage(int iBatteryPercentage) { m_batteryPercentage = iBatteryPercentage; if (UpmUpowerDBus::self()->hasBattery()) { m_percentageLabel->setText(QString("%1%").arg(m_batteryPercentage)); m_percentageLabel->show(); } else { m_percentageLabel->hide(); } } void powerwindow::setShowPowerLeftTime(int iShowPowerLeftTime) { m_showBatteryLeftTime = iShowPowerLeftTime; } void powerwindow::setBatteryLeftTime(qlonglong timeToFull, qlonglong timeToEmpty) { m_timeToFull = timeToFull; m_timeToEmpty = timeToEmpty; } void powerwindow::setPowerStateLabelForAcOnlineChanged() { // 添加无电池情况的处理 if (!UpmUpowerDBus::self()->hasBattery()) { m_powerStateLabel->setText(tr("No Battery detected")); m_acOnlineChange = true; return; } if (true == m_acOnlineState) { switch (m_batteryState) { case battery_state_unknown: qWarning() << "battery state unknown"; break; case battery_state_fully: m_powerStateLabel->setText(tr("Fully Charged")); break; case battery_state_discharging: //todo 有时候电池保护或者充满可能会出现该状态,不确定,不是100%时暂时先显示未充电 qWarning() << "battery state discharging"; if (100 == m_batteryPercentage) { m_powerStateLabel->setText(tr("Fully Charged")); } else { m_powerStateLabel->setText(tr("Not Charging")); } break; case battery_state_charging: m_powerStateLabel->setText(tr("Charging")); break; case battery_state_pending_charge: m_powerStateLabel->setText(tr("Not Charging")); break; case battery_state_empty: //todo qWarning() << "battery state empty"; break; case battery_state_last: //todo qWarning() << "battery state last"; break; default: break; } } else { m_powerStateLabel->setText(tr("Discharging")); } m_acOnlineChange = true; } void powerwindow::setPowerStateLabelForBatteryInfoChanged() { // 添加无电池情况的处理 if (!UpmUpowerDBus::self()->hasBattery()) { if (m_acOnlineState) { m_powerStateLabel->setText(tr("No Battery detected")); } m_acOnlineChange = true; return; } QString power_state_text(""); int hour = 0; int minute = 0; qint64 batteryLeftTime = 0; switch (m_batteryState) { case battery_state_unknown: case battery_state_fully: if (100 == m_batteryPercentage) { power_state_text = QString(tr("Fully Charged")); } break; case battery_state_charging: batteryLeftTime = m_timeToFull; if (false == m_showBatteryLeftTime || 0 == batteryLeftTime || true == m_batteryStateChanged || m_batteryPercentage > 95) { if (100 == m_batteryPercentage) { power_state_text = QString(tr("Fully Charged")); } else { power_state_text = QString(tr("Charging")); } } else { hour = batteryLeftTime / 3600; minute = ((batteryLeftTime) % 3600) / 60; if (0 == hour) { power_state_text = QString(tr("%1 minutes \nuntil fully charged")).arg(minute); } else if (hour > 10) { power_state_text = QString(tr("Charging")); } else { if (1 == hour) { if (1 == minute) { power_state_text = QString(tr("%1 hour %2 minute \nuntil fully charged")) .arg(hour).arg(minute); } else if (0 == minute) { power_state_text = QString(tr("%1 hour \nuntil fully charged")).arg(hour); } else { power_state_text = QString(tr("%1 hour %2 minutes \nuntil fully charged")) .arg(hour).arg(minute); } } else { if (1 == minute) { power_state_text = QString(tr("%1 hours %2 minute \nuntil fully charged")) .arg(hour).arg(minute); } else if (0 == minute) { power_state_text = QString(tr("%1 hours \nuntil fully charged")).arg(hour); } else { power_state_text = QString(tr("%1 hours %2 minutes \nuntil fully charged")) .arg(hour).arg(minute); } } } } break; case battery_state_discharging: batteryLeftTime = m_timeToEmpty; if (false == m_showBatteryLeftTime || 0 == batteryLeftTime || true == m_batteryStateChanged) { power_state_text = QString(tr("Discharging")); } else { hour = batteryLeftTime / 3600; minute = ((batteryLeftTime) % 3600) / 60; if (0 == hour) { power_state_text = QString(tr("%1 minutes \nremaining")).arg(minute); } else if (hour > 20) { power_state_text = QString(tr("Discharging")); } else { if (1 == hour) { if (1 == minute) { power_state_text = QString(tr("%1 hour %2 minute \nremaining")) .arg(hour).arg(minute); } else if (0 == minute) { power_state_text = QString(tr("%1 hour \nremaining")) .arg(hour); } else { power_state_text = QString(tr("%1 hour %2 minutes \nremaining")) .arg(hour).arg(minute); } } else { if (1 == minute) { power_state_text = QString(tr("%1 hours %2 minute \nremaining")) .arg(hour).arg(minute); } else if (0 == minute) { power_state_text = QString(tr("%1 hours \nremaining")) .arg(hour); } else { power_state_text = QString(tr("%1 hours %2 minutes \nremaining")) .arg(hour).arg(minute); } } } } break; case battery_state_pending_charge: power_state_text = QString(tr("Not Charging")); break; default: break; } m_powerStateLabel->setText(power_state_text); m_acOnlineChange = false; } void powerwindow::setPercentageLabelFontsize() { QFont font; font.setPointSize((int)(m_sysFontSize * 1.5)); m_percentageLabel->setFont(font); } void powerwindow::showPowerWindow() { if (false == m_isWayland) { resetWindowPosition(); // KWindowSystem::setState(this->winId(), NET::SkipTaskbar | NET::SkipPager | NET::SkipSwitcher); this->show(); powerwindow::slideWindowByPanelPosition(m_panelPosition); this->activateWindow(); } else { this->show(); resetWindowPosition(); powerwindow::slideWindowByPanelPosition(m_panelPosition); } } void powerwindow::resetWindowPosition() { QVariant value; int panelSize = 46; if (true == UpmGsettings::self()->getGsettingsConfig(GSETTINGS_KEY_PANEL_SIZE, value)) { panelSize = value.toInt(); } if (true == UpmGsettings::self()->getGsettingsConfig(GSETTINGS_KEY_PANEL_POSITION, value)) { m_panelPosition = value.toInt(); } QScreen* screen = QGuiApplication::screenAt(QCursor::pos()); if (screen == nullptr) { // 如果没有找到屏幕,直接返回,避免访问空指针 qWarning() << "无法获取当前光标所在屏幕,取消窗口位置重置"; return; } QRect availableGeometry = screen->geometry(); int x = 0; int y = 0; int margin = 8; switch (m_panelPosition) { case PanelPosition::panel_top: x = availableGeometry.x() + availableGeometry.width() - this->width() - margin; y = availableGeometry.y() + panelSize + margin; break; case PanelPosition::panel_left: x = availableGeometry.x() + panelSize + margin; y = availableGeometry.y() + availableGeometry.height() - this->height() - margin; break; case PanelPosition::panel_right: x = availableGeometry.x() + availableGeometry.width() - panelSize - this->width() - margin; y = availableGeometry.y() + availableGeometry.height() - this->height() - margin; break; default: x = availableGeometry.x() + availableGeometry.width() - this->width() - margin; y = availableGeometry.y() + availableGeometry.height() - panelSize - this->height() - margin; break; } m_windowPositionRect = QRect(x, y, this->width(), this->height()); this->setGeometry(m_windowPositionRect); } void powerwindow::slideWindowByPanelPosition(int panelPosition) { if(panelPosition == 0) { m_windowHelper->setSlideEffect(UkuiWindowHelper::Position::Bottom, 0, true); } else if (panelPosition == 1) { m_windowHelper->setSlideEffect(UkuiWindowHelper::Position::Top, 0, true); } else if(panelPosition == 2) { m_windowHelper->setSlideEffect(UkuiWindowHelper::Position::Left, 0, true); } else { m_windowHelper->setSlideEffect(UkuiWindowHelper::Position::Right, 0, true); } } void powerwindow::sliderValueChanged(int value) { qDebug() << "ac online state:" << m_acOnlineState << "slider value:" << value; if (value < 0 || value > 2) { return ; } int policy[3] = {EnergySaving, Balance, Performance}; if (true == m_acOnlineState) { UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_POWER_POLICY_AC, policy[value]); } else { UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_POWER_POLICY_BATTERY, policy[value]); } } void powerwindow::setSliderValue() { qDebug() << "ac online state:" << m_acOnlineState; int sliderPosition[3] = {2, 1, 0}; if (true == m_acOnlineState) { m_StateSlider->setValue(sliderPosition[m_powerPolicyAc]); } else { m_StateSlider->setValue(sliderPosition[m_powerPolicyBattery]); } } void powerwindow::paintEvent(QPaintEvent *event) { Q_UNUSED(event) // Qt6: QStyleOption::init() 已被移除,使用 initFrom() 替代 QStyleOption styleOption; styleOption.initFrom(this); QPainter painter(this); painter.setPen(Qt::NoPen); QColor color = palette().color(QPalette::Base); color.setAlphaF(m_transparency); QBrush brush = QBrush(color); painter.setBrush(brush); painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); painter.drawRect(styleOption.rect); } bool powerwindow::eventFilter(QObject *watched, QEvent *event) { if (watched == this) { if (event->type() == QEvent::WindowDeactivate) { hide(); return true; } else { return false; } } else { return false; } } void powerwindow::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape) { hide(); } QWidget::keyPressEvent(event); } ukui-power-manager/ukui-power-manager-tray/ukui-power-manager-tray.pro0000664000175000017500000000611015167661430025140 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-01-06T10:55:07 # #------------------------------------------------- QT += core gui dbus greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = ukui-power-manager-tray TEMPLATE = app target.path = /usr/bin INSTALLS += target # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 TRANSLATIONS+=\ translations/ukui-power-manager-tray_bo_CN.ts \ translations/ukui-power-manager-tray_zh_CN.ts \ translations/ukui-power-manager-tray_tr.ts \ translations/ukui-power-manager-tray_mn.ts \ translations/ukui-power-manager-tray_mn_MN.ts \ translations/ukui-power-manager-tray_zh_HK.ts QM_FILES_INSTALL_PATH = /usr/share/ukui-power-manager/tray/translations/ # CONFIG += lrelase not work for qt5.6, add those from lrelease.prf for compatibility qtPrepareTool(QMAKE_LRELEASE, lrelease) lrelease.name = lrelease lrelease.input = TRANSLATIONS lrelease.output = ${QMAKE_FILE_IN_BASE}.qm lrelease.commands = $$QMAKE_LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_OUT} lrelease.CONFIG = no_link QMAKE_EXTRA_COMPILERS += lrelease PRE_TARGETDEPS += compiler_lrelease_make_all for (translation, TRANSLATIONS) { translation = $$basename(translation) QM_FILES += $$OUT_PWD/$$replace(translation, \\..*$, .qm) } qm_files.files = $$QM_FILES qm_files.path = $$QM_FILES_INSTALL_PATH qm_files.CONFIG = no_check_exist INSTALLS += qm_files # So we can access it from main.cpp DEFINES += QM_FILES_INSTALL_PATH='\\"$${QM_FILES_INSTALL_PATH}\\"' LIBS += -lukui-log4qt CONFIG += c++11 no_keywords link_pkgconfig PKGCONFIG += gsettings-qt6 x11 kysdk-qtwidgets kysdk-waylandhelper kysdk-ukuiwindowhelper KF6WindowSystem INCLUDEPATH += $$PWD/../shared/include SOURCES += \ divider.cpp \ main.cpp \ powertray.cpp \ powerwindow.cpp \ kylable.cpp \ upm-gsettings/upm_gsettings.cpp \ upower-dbus/upm_upowerdbus.cpp \ upower-dbus/upowerbatterydbus.cpp \ upower-dbus/upowerdbus.cpp \ upower-dbus/upowerlinepowerdbus.cpp \ xatom-helper.cpp \ customstyle.cpp HEADERS += \ divider.h \ powertray.h \ powerwindow.h \ kylable.h \ upm-gsettings/upm_gsettings.h \ upower-dbus/upm_upowerdbus.h \ upower-dbus/upowerbatterydbus.h \ upower-dbus/upowerdbus.h \ upower-dbus/upowerlinepowerdbus.h \ xatom-helper.h \ customstyle.h FORMS += desktop.files += resources/ukui-power-manager-tray.desktop desktop.path = /etc/xdg/autostart/ INSTALLS += desktop # Default rules for deployment. ukui-power-manager/ukui-power-manager-tray/customstyle.h0000664000175000017500000002015715167661430022475 0ustar fengfeng/* * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. * * This program or library is free software; you can redistribute it * and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ #ifndef CUSTOMSTYLE_H #define CUSTOMSTYLE_H #include #include /*! * \brief The CustomStyle class * \details * 自定义QStyle * 基于QProxyStyle,默认使用QProxyStyle的实例绘制控件,你需要针对某一个控件重新实现若干对应的接口。 * QProxyStyle可以从现有的qt style实例化,我们只需要知道这个style的名字即可。 * 这种做法带来了不错的扩展性和自由度,因为我们不需要将某个style的代码直接引入我们的项目中, * 也能够“继承”这个style类进行二次开发。 * * 下面的方法展现了QStyle的所有的接口,使用QStyle进行控件的绘制使得qt应用能够进行风格的切换, * 从而达到不修改项目源码却对应用外观产生巨大影响的效果。 * * \note * 需要注意QStyle与QSS并不兼容,因为QSS本身其实上也是QStyle的一种实现,对一个控件而言,本身理论上只能 * 在同一时间调用唯一一个QStyle进行绘制。 */ class CustomStyle : public QProxyStyle { Q_OBJECT public: //proxyStyleName 是关于样式类型的,&proxyStyleName = "windows" 会造成toolTips的样式为windows类型样式 explicit CustomStyle(const QString &proxyStyleName = "ukui",bool multileWins=false, QObject *parent = nullptr); ~CustomStyle(); /*! * \brief drawComplexControl * \param control 比如ScrollBar,对应CC枚举类型 * \param option * \param painter * \param widget * \details * drawComplexControl用于绘制具有子控件的复杂控件,它本身一般不直接绘制控件, * 而是通过QStyle的其它方法将复杂控件分解成子控件再调用其它的draw方法绘制。 * 如果你需要重新实现一个复杂控件的绘制方法,首先考虑的应该是在不改变它原有的绘制流程的情况下, * 对它调用到的其它方法进行重写。 * * 如果你不想使用原有的绘制流程,那你需要重写这个接口,然后自己实现一切, * 包括背景的绘制,子控件的位置和状态计算,子控件的绘制等。 * 所以,你需要对这个控件有足够的了解之后再尝试直接重写这个接口。 */ virtual void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const; /*! * \brief drawControl * \param element 比如按钮,对应CE枚举类型 * \param option * \param painter * \param widget * \details * drawControl用于绘制基本控件元素,它本身一般只负责绘制控件的一部分或者一层。 * 如果你想要知道控件具体如何绘制,你需要同时研究这个控件的源码和QStyle中的源码, * 因为它们都有可能改变控件的绘制流程。 * * QStyle一般会遵循QCommonStyle的绘制流程,QCommenStyle是大部分主流style的最基类, * 它本身不能完全称之为一个主题,如果你直接使用它,你的控件将不能被正常绘制,因为它有可能只是 * 在特定的时候执行了特定却未实现的绘制方法,它更像一个框架或者规范。 */ virtual void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; virtual void drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const; virtual void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const; /*! * \brief drawPrimitive * \param element 背景绘制,对应PE枚举类型 * \param option * \param painter * \param widget * \details * drawPrimitive用于绘制控件背景,比如按钮和菜单的背景, * 我们一般需要判断控件的状态来绘制不同的背景, * 比如按钮的hover和点击效果。 */ virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const; virtual QStyle::SubControl hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget = nullptr) const; virtual QRect itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const; virtual QRect itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const; //virtual int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option, const QWidget *widget); virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const; /*! * \brief polish * \param widget * \details * polish用于对widget进行预处理,一般我们可以在polish中修改其属性, * 另外,polish是对动画和特效实现而言十分重要的一个方法, * 通过polish我们能够使widget和特效和动画形成对应关系。 */ virtual void polish(QWidget *widget); virtual void polish(QApplication *application); virtual void polish(QPalette &palette); virtual void unpolish(QWidget *widget); virtual void unpolish(QApplication *application); virtual QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget = nullptr) const; virtual QIcon standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; virtual QPalette standardPalette() const; /*! * \brief styleHint * \param hint 对应的枚举是SH * \param option * \param widget * \param returnData * \return * \details * styleHint比较特殊,通过它我们能够改变一些控件的绘制流程或者方式,比如说QMenu是否可以滚动。 */ virtual int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const; /*! * \brief subControlRect * \param control * \param option * \param subControl * \param widget * \return * \details * subControlRect返回子控件的位置和大小信息,这个方法一般在内置流程中调用, * 如果我们要重写某个绘制方法,可能需要用到它 */ virtual QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget = nullptr) const; /*! * \brief subElementRect * \param element * \param option * \param widget * \return * \details * 与subControlRect类似 */ virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget = nullptr) const; Q_SIGNALS: public Q_SLOTS: private: QString pluginName; bool multileWindow = false; }; #endif // CUSTOMSTYLE_H ukui-power-manager/ukui-power-manager-tray/powertray.h0000664000175000017500000000462715167661430022142 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef POWERTRAY_H #define POWERTRAY_H #include #include #include #include #include #include "upm-gsettings/upm_gsettings.h" #include "upower-dbus/upm_upowerdbus.h" #include "powerwindow.h" class PowerTray : public QObject { Q_OBJECT public: explicit PowerTray(QObject *parent = 0); ~PowerTray(); private: void initPowerTray(); void setTrayIconToolTipForAcOnlineChanged(bool acOnlineState, double percentage); void setTrayIconToolTipForBatteryInfoChanged(double percentage); void setTrayIcon(QString strIconName); void initTrayMenuUI(); void initPowerWindowUI(); void setPowerWindowProperties(); void updateBatteryInfo(); void acOnlineStateChangedAction(); bool isDesktop(); private: QTimer *m_acChangeTimer; bool m_isPowerSupplyChange; int m_showBatteryLeftTime = 1; QMenu *m_TrayMenu = nullptr; powerwindow *m_powerWindow = nullptr; QSystemTrayIcon *m_trayIcon; bool m_acOnlineState; int m_batteryState; double m_batteryPercentage; QString m_trayIconName; int m_oldPolicy; int m_correctionTime = 0; qint64 m_correctionTimeToEmpty; bool m_policyChanged = false; qint64 m_timeToFull; qint64 m_timeToEmpty; QDBusInterface *m_upowerInterface; private Q_SLOTS: void onActivatedIcon(QSystemTrayIcon::ActivationReason reason); void dealAcOnlineStateChanged(int, bool); void dealBatteryInfoChanged(int, QStringList); void dealPowerPolicyBatteryChanged(QVariant); void dealWakeUpSignal(bool); void dealDeviceChanged(); }; #endif // POWERTRAY_H ukui-power-manager/ukui-power-manager-tray/powerwindow.h0000664000175000017500000001003215167661430022455 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef POWERWINDOW_H #define POWERWINDOW_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kylable.h" #include "kslider.h" #include "divider.h" #include "kwindowsystem.h" #include "customstyle.h" #include "ukuiwindowhelper.h" #include "upm-gsettings/upm_gsettings.h" #include "upower-dbus/upm_upowerdbus.h" using namespace kdk; class powerwindow : public QWidget { Q_OBJECT public: explicit powerwindow(QWidget *parent = nullptr); ~powerwindow(); void setIconName(QString iconName); void setAcOnlineState(bool acOnlineState); void setBatteryState(int iBatteryState); void setBatteryPercentage(int iBatteryPercentage); void setShowPowerLeftTime(int iShowPowerLeftTime); void setBatteryLeftTime(qlonglong timeToFull, qlonglong timeToEmpty); void setPowerStateLabelForAcOnlineChanged(); void setPowerStateLabelForBatteryInfoChanged(); void setPercentageLabelFontsize(); void showPowerWindow(); void slideWindowByPanelPosition(int panelPosition); private : int m_deviceNum = 0; double m_sysFontSize; bool m_isWayland = false; int m_panelPosition; int m_batteryState = battery_state_last; bool m_batteryStateChanged = false; int m_batteryPercentage; bool m_acOnlineState = true; bool m_acOnlineChange; int m_showBatteryLeftTime; qint64 m_timeToFull; qint64 m_timeToEmpty; QString m_iconName; double m_transparency = 0.75; QGSettings *m_powerManagerGsettings; QGSettings *m_styleSettings; QVBoxLayout *m_pmainlayout = nullptr; QHBoxLayout *m_toplayout = nullptr; QHBoxLayout *m_firstlayout = nullptr; QHBoxLayout *m_lastlayout = nullptr; QHBoxLayout *m_statelayout = nullptr; QWidget *m_firstwidget; QWidget *m_lastWidget; QWidget *m_topwidget; QWidget *m_statewidget; QPushButton *m_iconButton; QLabel *m_percentageLabel; QLabel *m_powerStateLabel; QLabel *m_toplabel; QToolButton *m_enduranceIconButtun; QToolButton *m_performanceIconButtun; Divider *m_segmentationLine_1; Divider *m_segmentationLine_2; KSlider *m_StateSlider; KyLable *m_settingLabel; int m_powerPolicyAc; int m_powerPolicyBattery; QRect m_windowPositionRect; UkuiWindowHelper *m_windowHelper = nullptr; enum powerPolicy { Performance = 0, Balance, EnergySaving, }; enum PanelPosition { panel_bottom = 0, panel_top, panel_left, panel_right }; void initUI(); void initPlatformType(); void resetWindowPosition(); void setWindowProperty(); void setSliderValue(); bool eventFilter(QObject *watched, QEvent *event); void keyPressEvent(QKeyEvent *event); private Q_SLOTS: void sliderValueChanged(int); protected: void paintEvent(QPaintEvent *event); }; #endif // POWERWINDOW_H ukui-power-manager/ukui-power-manager-tray/powertray.cpp0000664000175000017500000003611215167661430022467 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "powertray.h" #include "powerwindow.h" #include "kwindowsystem.h" #include "dmi_chassis_type.h" PowerTray::PowerTray(QObject *parent) : QObject(parent) { if (!UpmUpowerDBus::self()->hasBattery() && !UpmUpowerDBus::self()->getAcOnlineState()) { qDebug() << "No battery and no AC adapter, Program exit"; exit(0); } if (isDesktop()) { qDebug() << "This is a desktop, Program exit"; exit(0); } initPowerTray(); QDBusConnection::systemBus().connect("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "PrepareForSleep", this, SLOT(dealWakeUpSignal(bool))); } PowerTray::~PowerTray() { if (nullptr != m_TrayMenu) { delete m_TrayMenu; m_TrayMenu = nullptr; } if (nullptr != m_powerWindow) { delete m_powerWindow; m_powerWindow = nullptr; } } void PowerTray::initPowerTray() { QVariant value; if (true == UpmGsettings::self()->getGsettingsConfig(GSETTINGS_KEY_DISPLAY_LEFT_TIME, value)) { m_showBatteryLeftTime = value.toInt(); } connect(UpmGsettings::self(), &UpmGsettings::dispalyLeftTimeOfChargeAndDischargeChanged, this, [=](QVariant value) { m_showBatteryLeftTime = value.toInt(); updateBatteryInfo(); setTrayIconToolTipForBatteryInfoChanged(m_batteryPercentage); setPowerWindowProperties(); m_powerWindow->setPowerStateLabelForBatteryInfoChanged(); }); if (true == UpmGsettings::self()->getGsettingsConfig(GSETTINGS_KEY_POWER_POLICY_BATTERY, value)) { m_oldPolicy = value.toInt(); } m_acChangeTimer = new QTimer(this); m_isPowerSupplyChange = false; connect(m_acChangeTimer, &QTimer::timeout, this, [=](){ m_isPowerSupplyChange = false; m_acChangeTimer->stop(); }); updateBatteryInfo(); m_upowerInterface = new QDBusInterface(UPOWER_SERVICE, UPOWER_DISPLAY_PATH, UPOWER_DISPLAY_INTERFACE, QDBusConnection::sessionBus()); if (!m_upowerInterface->isValid()) { qWarning() << "Failed to connect to UPower D-Bus interface."; } m_trayIcon = new QSystemTrayIcon(this); setTrayIconToolTipForAcOnlineChanged(m_acOnlineState, m_batteryPercentage); m_trayIconName = UpmUpowerDBus::self()->getBatteryIconName(); setTrayIcon(m_trayIconName); initTrayMenuUI(); initPowerWindowUI(); connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(onActivatedIcon(QSystemTrayIcon::ActivationReason))); connect(UpmUpowerDBus::self(), &UpmUpowerDBus::acOnlineStateChanged, this, &PowerTray::dealAcOnlineStateChanged); connect(UpmUpowerDBus::self(), &UpmUpowerDBus::batteryInfoChanged, this, &PowerTray::dealBatteryInfoChanged); connect(UpmGsettings::self(), &UpmGsettings::powerPolicyBatteryChanged, this, &PowerTray::dealPowerPolicyBatteryChanged); connect(UpmUpowerDBus::self(), &UpmUpowerDBus::deviceChanged, this, &PowerTray::dealDeviceChanged); } void PowerTray::initTrayMenuUI() { qDebug() << "init tray menu ui"; m_TrayMenu = new QMenu(); m_TrayMenu->setAttribute(Qt::WA_TranslucentBackground); m_trayIcon->setContextMenu(m_TrayMenu); QAction *setPreference = new QAction(m_TrayMenu); QIcon icon = QIcon::fromTheme("document-page-setup-symbolic"); setPreference->setIcon(icon); setPreference->setText(tr("SetPower")); connect(setPreference, &QAction::triggered,[=]{QProcess::startDetached(QString("ukui-control-center -m Power"));}); m_TrayMenu->addAction(setPreference); } void PowerTray::initPowerWindowUI() { qDebug() << "init power window ui"; m_powerWindow = new powerwindow(); m_powerWindow->hide(); setPowerWindowProperties(); m_powerWindow->setPowerStateLabelForAcOnlineChanged(); } void PowerTray::setPowerWindowProperties() { m_powerWindow->setIconName(m_trayIconName); m_powerWindow->setAcOnlineState(m_acOnlineState); m_powerWindow->setBatteryState(m_batteryState); m_powerWindow->setBatteryPercentage(m_batteryPercentage); m_powerWindow->setShowPowerLeftTime(m_showBatteryLeftTime); m_powerWindow->setBatteryLeftTime(m_timeToFull, m_timeToEmpty); } void PowerTray::setTrayIconToolTipForAcOnlineChanged(bool acOnlineState, double percentage) { //添加无电池情况的处理 if(!UpmUpowerDBus::self()->hasBattery()) { if (true == acOnlineState) { m_trayIcon->setToolTip(tr("No battery detected")); QDBusReply reply = m_upowerInterface->call("SetBatteryTooltip",m_trayIcon->toolTip()); } return; } if (true == acOnlineState) { if (100 == percentage) { m_trayIcon->setToolTip(tr("Fully Charged (100%)")); } else { m_trayIcon->setToolTip(tr("%1% available (plugged in)").arg(percentage)); } } else { m_trayIcon->setToolTip(tr("%1% remaining").arg(percentage)); } QDBusReply reply = m_upowerInterface->call("SetBatteryTooltip",m_trayIcon->toolTip()); } void PowerTray::setTrayIconToolTipForBatteryInfoChanged(double percentage) { //添加无电池情况的处理 if(!UpmUpowerDBus::self()->hasBattery()) { if (true == m_acOnlineState) { m_trayIcon->setToolTip(tr("No battery detected")); QDBusReply reply = m_upowerInterface->call("SetBatteryTooltip",m_trayIcon->toolTip()); } return; } qint64 batteryLeftTime = 0; int hour = 0; switch (UpmUpowerDBus::self()->getBatteryState()) { case battery_state_unknown: case battery_state_fully: if (100 == percentage) { m_trayIcon->setToolTip(tr("Fully Charged (100%)")); } else { m_trayIcon->setToolTip(tr("%1% remaining").arg(percentage)); } break; case battery_state_charging: batteryLeftTime = m_timeToFull; if (0 == m_showBatteryLeftTime || 0 == batteryLeftTime || percentage > 95 ) { if (100 == percentage) { m_trayIcon->setToolTip(tr("Fully Charged (100%)")); } else { m_trayIcon->setToolTip(tr("%1% available (plugged in)").arg(percentage)); } } else { hour = batteryLeftTime / 3600; if (0 == hour) { m_trayIcon->setToolTip(tr("%1 min to fully charge (%2%)") .arg(((batteryLeftTime) % 3600) / 60) .arg(percentage)); } else if (hour > 10) { m_trayIcon->setToolTip(tr("%1% available (plugged in)").arg(percentage)); } else { m_trayIcon->setToolTip(tr("%1 hr %2 min to fully charge (%3%)") .arg(hour) .arg(((batteryLeftTime) % 3600) / 60) .arg(percentage)); } } break; case battery_state_discharging: batteryLeftTime = m_timeToEmpty; if (0 == m_showBatteryLeftTime || 0 == batteryLeftTime) { m_trayIcon->setToolTip(tr("%1% remaining").arg(percentage)); } else { hour = batteryLeftTime / 3600; if (0 == hour) { m_trayIcon->setToolTip(tr("%1 min (%2%) remaining") .arg(((batteryLeftTime) % 3600) / 60) .arg(percentage)); } else if (hour > 20) { m_trayIcon->setToolTip(tr("%1% remaining").arg(percentage)); } else { m_trayIcon->setToolTip(tr("%1 hr %2 min (%3%) remaining") .arg(hour) .arg(((batteryLeftTime) % 3600) / 60) .arg(percentage)); } } break; default: m_trayIcon->setToolTip(tr("%1% remaining").arg(percentage)); break; } QDBusReply reply = m_upowerInterface->call("SetBatteryTooltip",m_trayIcon->toolTip()); } void PowerTray::setTrayIcon(QString strIconName) { qDebug() << "icon name is : " << strIconName; if (!strIconName.isNull()) { QIcon icon = QIcon::fromTheme(strIconName); m_trayIcon->setIcon(icon); m_trayIcon->show(); QDBusReply reply = m_upowerInterface->call("SetShowIcon",true); } else { m_trayIcon->hide(); QDBusReply reply = m_upowerInterface->call("SetShowIcon",false); } } void PowerTray::onActivatedIcon(QSystemTrayIcon::ActivationReason reason) { if (reason == 3) { bool isVisible = m_powerWindow->isVisible(); qDebug() << "power window is visible:" << isVisible; if (true == isVisible) { m_powerWindow->hide(); } else { m_powerWindow->showPowerWindow(); } } else { qDebug() << "on Activated Icon reason:" << reason; } } void PowerTray::acOnlineStateChangedAction() { updateBatteryInfo(); //deal tray icon setTrayIconToolTipForAcOnlineChanged(m_acOnlineState, m_batteryPercentage); m_trayIconName = UpmUpowerDBus::self()->getBatteryIconName(); setTrayIcon(m_trayIconName); //deal power window setPowerWindowProperties(); m_powerWindow->setPowerStateLabelForAcOnlineChanged(); } void PowerTray::dealAcOnlineStateChanged(int index, bool value) { qDebug() << "power tray ac online state changed"; m_isPowerSupplyChange = true; m_acChangeTimer->start(120 * 1000); acOnlineStateChangedAction(); if (false == m_acOnlineState) { qInfo() << "unplug power"; } } void PowerTray::dealBatteryInfoChanged(int index, QStringList batteryInfoChangedList) { qDebug() << "power tray battery info changed"; if (true == m_isPowerSupplyChange) { qDebug() << "ac online changed, not deal battery info changed"; acOnlineStateChangedAction(); return ; } updateBatteryInfo(); if (false == m_acOnlineState && m_batteryPercentage < 2) { qInfo() << "battery remaining 1%"; } //deal tray icon setTrayIconToolTipForBatteryInfoChanged(m_batteryPercentage); QString trayIconName = UpmUpowerDBus::self()->getBatteryIconName(); if (m_trayIconName != trayIconName) { m_trayIconName = trayIconName; setTrayIcon(m_trayIconName); } //deal power window setPowerWindowProperties(); m_powerWindow->setPowerStateLabelForBatteryInfoChanged(); } void PowerTray::dealPowerPolicyBatteryChanged(QVariant value) { if (true == m_isPowerSupplyChange) { return; } if (false == UpmUpowerDBus::self()->getAcOnlineState()) { m_policyChanged = true; QVector timeCoefficientVector; timeCoefficientVector << 0.03 << 0.04 << 0.05 << 0.06; double timeCoefficient = 0.07; int timeCoefficientIndex = m_batteryPercentage / 10; if (timeCoefficientIndex < timeCoefficientVector.size()) { timeCoefficient = timeCoefficientVector[timeCoefficientIndex]; } int newPolicy = value.toInt(); if (1 == m_oldPolicy - newPolicy) { m_timeToEmpty -= (m_timeToEmpty * timeCoefficient); } else if (2 == m_oldPolicy - newPolicy) { m_timeToEmpty -= (m_timeToEmpty * timeCoefficient * 2); } else if (-1 == m_oldPolicy - newPolicy) { m_timeToEmpty += (m_timeToEmpty * timeCoefficient); } else if (-2 == m_oldPolicy - newPolicy) { m_timeToEmpty += (m_timeToEmpty * timeCoefficient * 2); } else { ; } m_oldPolicy = newPolicy; //deal tray icon setTrayIconToolTipForBatteryInfoChanged(m_batteryPercentage); QString trayIconName = UpmUpowerDBus::self()->getBatteryIconName(); if (m_trayIconName != trayIconName) { m_trayIconName = trayIconName; setTrayIcon(m_trayIconName); } //deal power window setPowerWindowProperties(); m_powerWindow->setPowerStateLabelForBatteryInfoChanged(); m_policyChanged = false; } } void PowerTray::dealWakeUpSignal(bool isSleepState) { if (true == isSleepState) { qDebug() << "The computer is going to sleep "; } else { qDebug() << "The computer wakes up "; //机器刚从休眠或睡眠中唤醒时,此时不显示时间 m_isPowerSupplyChange = true; m_acChangeTimer->start(60 * 1000); acOnlineStateChangedAction(); } } void PowerTray::dealDeviceChanged() { qDebug() << "Device changed, refresh battery info"; updateBatteryInfo(); //deal tray icon setTrayIconToolTipForBatteryInfoChanged(m_batteryPercentage); m_trayIconName = UpmUpowerDBus::self()->getBatteryIconName(); setTrayIcon(m_trayIconName); //deal power window setPowerWindowProperties(); m_powerWindow->setPowerStateLabelForBatteryInfoChanged(); } void PowerTray::updateBatteryInfo() { m_acOnlineState = UpmUpowerDBus::self()->getAcOnlineState(); m_batteryState = UpmUpowerDBus::self()->getBatteryState(); m_batteryPercentage = UpmUpowerDBus::self()->getBatteryPercentage(); m_timeToFull = UpmUpowerDBus::self()->getTimeToFull(); if (false == m_policyChanged) { m_timeToEmpty = UpmUpowerDBus::self()->getTimeToEmpty(); } } bool PowerTray::isDesktop() { QFile file("/sys/class/dmi/id/chassis_type"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "Failed to open chassis_type file"; return false; } QString chassisTypeStr = file.readAll().trimmed(); file.close(); bool ok = false; int chassisTypeInt = chassisTypeStr.toInt(&ok); if (!ok) { qWarning() << "Invalid chassis_type format:" << chassisTypeStr; return false; } if (static_cast(chassisTypeInt) == DmiChassisType::Desktop) { return true; // 台式机 } return false; // 非台式机 } ukui-power-manager/ukui-power-manager-tray/upm-gsettings/0000775000175000017500000000000015167661430022532 5ustar fengfengukui-power-manager/ukui-power-manager-tray/upm-gsettings/upm_gsettings.h0000664000175000017500000000675415167661430025607 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef UPM_GSETTINGS_H #define UPM_GSETTINGS_H #include #include #include #include //power gsettings 配置 #define POWER_MANAGER_SETTINGS "org.ukui.power-manager" //电源策略(0:节能 1:平衡 2:性能) #define GSETTINGS_KEY_POWER_POLICY_AC "powerPolicyAc" #define GSETTINGS_KEY_POWER_POLICY_BATTERY "powerPolicyBattery" #define GSETTINGS_KEY_DISPLAY_LEFT_TIME "dispalyLeftTimeOfChargeAndDischarge" //任务栏 gsettings 配置 #define PANEL_SETTINGS "org.ukui.panel.settings" #define GSETTINGS_KEY_PANEL_SIZE "panelsize" #define GSETTINGS_KEY_PANEL_POSITION "panelposition" //style gsettings 配置 #define STYLE_SETTINGS "org.ukui.style" #define GSETTINGS_KEY_SYSTEM_FONT_SIZE "systemFontSize" #define GSETTINGS_KEY_STYLE_NAME "styleName" //control-center gsettings 配置 #define CONTROL_CENTER_SETTINGS "org.ukui.control-center.personalise" #define GSETTINGS_KEY_TRANSPARENCY_KEY "transparency" //dbus配置 #define UPOWER_SERVICE "org.ukui.upower" #define UPOWER_DISPLAY_PATH "/upower/BatteryInfo" #define UPOWER_DISPLAY_INTERFACE "org.ukui.upower.battery" class UpmGsettings : public QObject { Q_OBJECT public: explicit UpmGsettings(QObject *parent = nullptr); ~UpmGsettings(); static UpmGsettings* self(); typedef void (UpmGsettings::*pSignalFun)(QVariant); private: QGSettings *m_powerGsettings; QStringList m_allPowerKey; QGSettings *m_panelGsettings; QStringList m_allPanelKey; QGSettings *m_styleGsettings; QStringList m_allStyleKey; QGSettings *m_controlCenterGsettings; QStringList m_allControlCenterKey; QHash m_qHashValue; QHash m_qHashSignalsFuns; void initPowerGsettings(); void initPanelGsettings(); void initStyleGsettings(); void initControlCenterGsettings(); void addConfigMonitor(const QString &configName, pSignalFun signalFun); Q_SIGNALS: void powerPolicyAcChanged(QVariant); void powerPolicyBatteryChanged(QVariant); void dispalyLeftTimeOfChargeAndDischargeChanged(QVariant); void percentageActionChanged(QVariant); void actionCriticalBatteryChanged(QVariant); void panelsizeChanged(QVariant); void panelpositionChanged(QVariant); void systemFontSizeChanged(QVariant); void styleNameChanged(QVariant); void transparencyChanged(QVariant); private Q_SLOTS: void dealGsettingsKeyChanged(const QString &key); public: void setGsettingsConfig(const QString &configName, QVariant value); bool getGsettingsConfig(const QString &configName, QVariant &value); }; #endif // UPM_GSETTINGS_H ukui-power-manager/ukui-power-manager-tray/upm-gsettings/upm_gsettings.cpp0000664000175000017500000001421615167661430026132 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "upm_gsettings.h" #include Q_GLOBAL_STATIC(UpmGsettings, s_upmGsettings) UpmGsettings::UpmGsettings(QObject *parent) : QObject(parent) { initPowerGsettings(); initPanelGsettings(); initStyleGsettings(); initControlCenterGsettings(); } UpmGsettings::~UpmGsettings() { delete m_powerGsettings; delete m_panelGsettings; delete m_styleGsettings; delete m_controlCenterGsettings; } UpmGsettings *UpmGsettings::self() { return s_upmGsettings; } void UpmGsettings::dealGsettingsKeyChanged(const QString &key) { if (true == m_qHashValue.contains(key)) { if (m_allPowerKey.contains(key)) { m_qHashValue[key] = m_powerGsettings->get(key); } else if (m_allPanelKey.contains(key)) { m_qHashValue[key] = m_panelGsettings->get(key); } else if (m_allStyleKey.contains(key)) { m_qHashValue[key] = m_styleGsettings->get(key); } else if (m_allControlCenterKey.contains(key)) { m_qHashValue[key] = m_controlCenterGsettings->get(key); } Q_EMIT (this->*m_qHashSignalsFuns[key])(m_qHashValue[key]); qDebug() << "key" << key << "changed"; } else { qDebug() << "this key:" << key << "is not monitored!"; } } void UpmGsettings::setGsettingsConfig(const QString &configName, QVariant value) { if (true == m_qHashValue.contains(configName)) { m_qHashValue[configName] = value; if (m_allPowerKey.contains(configName)) { m_powerGsettings->set(configName, value); } else if (m_allPanelKey.contains(configName)) { m_panelGsettings->set(configName, value); } else if (m_allStyleKey.contains(configName)) { m_styleGsettings->set(configName, value); } else if (m_allControlCenterKey.contains(configName)) { m_controlCenterGsettings->set(configName, value); } qDebug() << "set key:" << configName << "value:" << value; } else { qInfo() << "this key:" << configName << "is not monitored!"; } } bool UpmGsettings::getGsettingsConfig(const QString &configName, QVariant &value) { qDebug() << "get key:" << configName; if (true == m_qHashValue.contains(configName)) { value = m_qHashValue[configName]; return true; } qInfo() << "this key:" << configName << "is not monitored!"; return false; } void UpmGsettings::addConfigMonitor(const QString &configName, pSignalFun signalFun) { if (m_allPowerKey.contains(configName)) { m_qHashValue[configName] = m_powerGsettings->get(configName); m_qHashSignalsFuns[configName] = signalFun; qDebug() << "power gsetting:" << configName << "to be monitored!"; } else if (m_allPanelKey.contains(configName)) { m_qHashValue[configName] = m_panelGsettings->get(configName); m_qHashSignalsFuns[configName] = signalFun; qDebug() << "panel gsetting:" << configName << "to be monitored!"; } else if (m_allStyleKey.contains(configName)) { m_qHashValue[configName] = m_styleGsettings->get(configName); m_qHashSignalsFuns[configName] = signalFun; qDebug() << "style gsetting:" << configName << "to be monitored!"; } else if (m_allControlCenterKey.contains(configName)) { m_qHashValue[configName] = m_controlCenterGsettings->get(configName); m_qHashSignalsFuns[configName] = signalFun; qDebug() << "control center gsetting:" << configName << "to be monitored!"; } else { qInfo() << "without this key:" << configName; } } void UpmGsettings::initPowerGsettings() { m_powerGsettings = new QGSettings(QByteArray(POWER_MANAGER_SETTINGS)); m_allPowerKey = m_powerGsettings->keys(); addConfigMonitor(GSETTINGS_KEY_POWER_POLICY_AC, &UpmGsettings::powerPolicyAcChanged); addConfigMonitor(GSETTINGS_KEY_POWER_POLICY_BATTERY, &UpmGsettings::powerPolicyBatteryChanged); addConfigMonitor(GSETTINGS_KEY_DISPLAY_LEFT_TIME, &UpmGsettings::dispalyLeftTimeOfChargeAndDischargeChanged); connect(m_powerGsettings, &QGSettings::changed, this, &UpmGsettings::dealGsettingsKeyChanged); } void UpmGsettings::initPanelGsettings() { m_panelGsettings = new QGSettings(QByteArray(PANEL_SETTINGS)); m_allPanelKey = m_panelGsettings->keys(); addConfigMonitor(GSETTINGS_KEY_PANEL_SIZE, &UpmGsettings::panelsizeChanged); addConfigMonitor(GSETTINGS_KEY_PANEL_POSITION, &UpmGsettings::panelpositionChanged); connect(m_panelGsettings, &QGSettings::changed, this, &UpmGsettings::dealGsettingsKeyChanged); } void UpmGsettings::initStyleGsettings() { m_styleGsettings = new QGSettings(QByteArray(STYLE_SETTINGS)); m_allStyleKey = m_styleGsettings->keys(); addConfigMonitor(GSETTINGS_KEY_SYSTEM_FONT_SIZE, &UpmGsettings::systemFontSizeChanged); addConfigMonitor(GSETTINGS_KEY_STYLE_NAME, &UpmGsettings::styleNameChanged); connect(m_styleGsettings, &QGSettings::changed, this, &UpmGsettings::dealGsettingsKeyChanged); } void UpmGsettings::initControlCenterGsettings() { m_controlCenterGsettings = new QGSettings(QByteArray(CONTROL_CENTER_SETTINGS)); m_allControlCenterKey = m_controlCenterGsettings->keys(); addConfigMonitor(GSETTINGS_KEY_TRANSPARENCY_KEY, &UpmGsettings::transparencyChanged); connect(m_controlCenterGsettings, &QGSettings::changed, this, &UpmGsettings::dealGsettingsKeyChanged); } ukui-power-manager/3rd/0000775000175000017500000000000015167661430013720 5ustar fengfengukui-power-manager/3rd/tlp/0000775000175000017500000000000015167661430014517 5ustar fengfengukui-power-manager/3rd/tlp/func.d/0000775000175000017500000000000015167661430015674 5ustar fengfengukui-power-manager/3rd/tlp/func.d/30-tlp-func-rf-sw0000664000175000017500000003373315167661430020634 0ustar fengfeng#!/bin/sh # tlp-func-rf-sw - Radio Switch Functions # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, tlp-func-rf # shellcheck disable=SC2034 # ---------------------------------------------------------------------------- # Constants readonly NMCLI=nmcli readonly RFKILL="rfkill" readonly RFKD="/dev/rfkill" readonly ALLDEV="bluetooth nfc wifi wwan" readonly RDW_NM_LOCK="rdw_nm" readonly RDW_DOCK_LOCK="rdw_dock" readonly RDW_NM_LOCKTIME=2 readonly RDW_KILL="rdw_kill" readonly RFSTATEFILE=$VARDIR/rfkill_saved # ---------------------------------------------------------------------------- # Functions get_devc () { # get control device for radio type # $1: rftype bluetooth/nfc/wifi/wwan # retval $_devc: sysdev, $_devs: device state # $_rfkdev: 1/0=is/is not an rfkill device, # $_devon, $_devoff: value to write directly to the sysdev # to achieve the desired switch state local i # preset retvals _devc="" _devs=254 _rfkdev="1" _devon="1" _devoff="0" case "$1" in wwan|bluetooth|nfc) for i in /sys/class/rfkill/rfkill* ; do if [ "$(read_sysf "$i/type")" = "$1" ]; then _devc="$i/state" echo_debug "rf" "get_devc($1) = $_devc" return 0 fi done ;; wifi) for i in /sys/bus/pci/drivers/ipw2?00/*/rf_kill; do if [ -f "$i" ]; then _devc="$i" _rfkdev="0" _devon="0" _devoff="1" echo_debug "rf" "get_devc($1) = $_devc" return 0 fi done for i in /sys/class/rfkill/rfkill* ; do if [ "$(read_sysf "$i/type")" = "wlan" ]; then _devc="$i/state" echo_debug "rf" "get_devc($1) = $_devc" return 0 fi done ;; *) echo "Error: unknown device type \"$1\"" 1>&2 echo_debug "rf" "get_devc($1).unknown_type" return 0 ;; esac echo_debug "rf" "get_devc($1).not_present" return 0 } get_devs () { # get radio device state -- $1: rftype; retval $_devs: 0=off/1=on if [ -n "$_devc" ]; then _devs="$(read_sysf "$_devc")" case "$_devs" in 0|1) # invert state when not a rfkill device [ "$_rfkdev" = "0" ] && _devs=$((_devs ^ _devoff)) ;; 2) ;; # hard blocked device *) _devs=3 # invalid state esac fi echo_debug "rf" "get_devs($1) = $_devs" return 0 } err_no_root_priv () { # check root privilege echo "Error: missing root privilege." 1>&2 echo_debug "rf" "$1.missing_root_privilege" return 0 } test_rfkill_perms () { # test if either root priv or rfkill device writable test_root || [ -w $RFKD ] } check_nm () { # test if NetworkManager is running and nmcli is installed cmd_exists $NMCLI } invoke_nmcli () { # call nmcli with radio option according to the program version # $1: rftype, $2: on/off, $3: caller; rc: last nmcli rc local rc check_nm || return 0 # return if NetworkManager not running $NMCLI radio "$1" "$2" > /dev/null 2>&1; rc=$? echo_debug "rf" "invoke_nmcli($1, $2).radio: rc=$rc" return $rc } device_state () { # get radio type state -- $1: rftype; retval $_devc, $_devs: 0=off/1=on echo_debug "rf" "device_state($1)" get_devc "$1" get_devs "$1" } device_switch () { # switch radio type state # $1: rftype, $2: 1/on/0/off/toggle # $3: lock id, $4: lock duration # rc: 0=switched/1=invalid device or operation/ # 2=hard blocked/3=invalid state/4=no change # retval $_devc, $_devs: 0=off/1=on local curst newst devn echo_debug "rf" "device_switch($1, $2, $3, $4)" get_devc "$1" # quit if no device if [ -z "$_devc" ]; then echo_debug "rf" "device_switch($1, $2).no_device: rc=1" return 1 fi # quit if invalid operation if ! wordinlist "$2" "on 1 off 0 toggle"; then echo_debug "rf" "device_switch($1, $2).invalid_op: rc=1" return 1 fi # get current device state get_devs "$1" curst="$_devs" # quit if device state is hard blocked or invalid if [ "$_devs" -ge 2 ]; then case "$_devs" in 2) echo_debug "rf" "device_switch($1, $2).hard_blocked: rc=$_devs" ;; *) echo_debug "rf" "device_switch($1, $2).invalid_state: rc=$_devs" ;; esac return "$_devs" fi # determine desired device state case "$2" in 1|on) newst=1 ;; 0|off) newst=0 ;; toggle) newst=$((curst ^ 1)) ;; esac # compare current and desired device state if [ "$curst" = "$newst" ]; then # desired matches current state --> do nothing echo_debug "rf" "device_switch($1, $2).desired_state" else # desired does not match current state --> do switch # set timed lock if required [ -n "$3" ] && [ -n "$4" ] && [ "$1" != "bluetooth" ] && \ set_timed_lock "$3" "$4" if [ "$_rfkdev" = "1" ] && cmd_exists $RFKILL ; then # switch device with rfkill if test_rfkill_perms ; then # use rfkill echo_debug "rf" "device_switch($1, $2).rfkill" case "$newst" in 1) $RFKILL unblock "$1" > /dev/null 2>&1 ;; 0) $RFKILL block "$1" > /dev/null 2>&1 ;; *) ;; esac # record device state after rfkill get_devs "$1" else # missing permission to rfkill err_no_root_priv "device_switch($1, $2).rfkill" fi else # switch device with direct write case "$newst" in 1) devn="$_devon" ;; 0) devn="$_devoff" ;; esac if test_root ; then write_sysf "$devn" "$_devc" echo_debug "rf" "device_switch($1, $2).devc: rc=$?" # record device state after direct write get_devs "$1" else err_no_root_priv "device_switch($1, $2).devc" fi fi fi # states did not match # quit if device state is hard blocked or invalid if [ "$_devs" -ge 2 ]; then case "$_devs" in 2) echo_debug "rf" "device_switch($1, $2).hard_blocked: rc=$_devs" ;; *) echo_debug "rf" "device_switch($1, $2).invalid_state: rc=$_devs" ;; esac return "$_devs" fi # compare old and new device state if [ "$curst" = "$_devs" ]; then # state did not change echo_debug "rf" "device_switch($1, $2).no_change: rc=4" return 4 else echo_debug "rf" "device_switch($1, $2).ok: rc=0" return 0 fi } echo_device_state () { # print radio type state -- $1: rftype, $2: state case "$1" in bluetooth) devstr="bluetooth" ;; nfc) devstr="nfc " ;; wifi) devstr="wifi " ;; wwan) devstr="wwan " ;; *) devstr=$1 ;; esac case "$2" in 0) echo "$devstr = off (software)" ;; 1) echo "$devstr = on" ;; 2) echo "$devstr = off (hardware)" ;; 254) echo "$devstr = none (no device)" ;; *) echo "$devstr = invalid state" esac return 0 } # shellcheck disable=SC2120 save_device_states () { # save radio states -- $1: list of rftypes # rc: 0=ok/1=create failed/2=write failed local dev local devlist="${1:-$ALLDEV}" # when arg empty -> use all local rc=0 # create empty state file if [ -d "$VARDIR" ] && { : > "$RFSTATEFILE"; } 2> /dev/null; then # iterate over all possible devices -> save state in file for dev in $devlist; do device_state "$dev" { printf '%s\n' "$dev $_devs" >> "$RFSTATEFILE"; } 2> /dev/null || rc=2 done else # create failed rc=1 fi echo_debug "rf" "save_device_states($devlist): $RFSTATEFILE; rc=$rc" return $rc } restore_device_states () { # restore radio type states # rc: 0=ok/1=state file nonexistent local sline local rc=0 if [ -f "$RFSTATEFILE" ]; then # read state file # shellcheck disable=SC2162 while read -r sline; do # shellcheck disable=SC2086 set -- $sline # read dev, state into $1, $2 device_switch "$1" "$2" done < "$RFSTATEFILE" else # state file nonexistent rc=1 fi echo_debug "rf" "restore_device_states: $RFSTATEFILE; rc=$rc" return $rc } set_radio_device_states () { # set/initialize all radio states # $1: start/stop/1/0/radiosw # called from init scripts or upon change of power source local dev devs2disable devs2enable restore local quiet=0 # save/restore mode is disabled by default if [ "$1" != "radiosw" ]; then restore="$RESTORE_DEVICE_STATE_ON_STARTUP" else restore=0 fi if [ "$restore" = "1" ]; then # "save/restore" mode echo_debug "rf" "set_radio_device_states($1).restore" case $1 in start) if restore_device_states; then echo "Radio device states restored." else echo "No saved radio device states found." fi ;; stop) # shellcheck disable=SC2119 save_device_states echo "Radio device states saved." ;; esac else # "disable/enable on startup/shutdown or bat/ac" or "radiosw" mode case $1 in start) # system startup devs2disable="$DEVICES_TO_DISABLE_ON_STARTUP" devs2enable="$DEVICES_TO_ENABLE_ON_STARTUP" ;; stop) # system shutdown devs2disable="" devs2enable="" if [ "$X_WIFI_ON_SHUTDOWN" != "0" ]; then # NM workaround: if # 1. disable wifi is configured somehow, and # 2. wifi is not explicitly configured for shutdown # then re-enable wifi on shutdown to prepare for startup if wordinlist "wifi" "$DEVICES_TO_DISABLE_ON_BAT $DEVICES_TO_DISABLE_ON_BAT_NOT_IN_USE $DEVICES_TO_DISABLE_ON_LAN_CONNECT $DEVICES_TO_DISABLE_ON_WIFI_CONNECT $DEVICES_TO_DISABLE_ON_WWAN_CONNECT" && \ ! wordinlist "wifi" "$devs2disable $devs2enable"; then devs2enable="wifi $devs2enable" fi fi ;; 1) # battery power --> build disable list quiet=1 # do not display progress devs2enable="" devs2disable="${DEVICES_TO_DISABLE_ON_BAT:-}" # check configured list for connected devices for dev in ${DEVICES_TO_DISABLE_ON_BAT_NOT_IN_USE:-}; do # if device is not connected and not in list yet --> add to disable list { case $dev in bluetooth) any_bluetooth_in_use ;; wifi) any_wifi_in_use ;; wwan) any_wwan_in_use ;; esac } || wordinlist "$dev" "$devs2disable" || devs2disable="$dev $devs2disable" done devs2disable="${devs2disable# }" ;; 0) # AC power --> build enable list quiet=1 # do not display progress devs2enable="${DEVICES_TO_ENABLE_ON_AC:-}" devs2disable="" ;; radiosw) devs2disable="" devs2enable="$DEVICES_TO_ENABLE_ON_RADIOSW" ;; esac echo_debug "rf" "set_radio_device_states($1): enable=$devs2enable disable=$devs2disable" # disable configured radios if [ -n "$devs2disable" ]; then [ "$quiet" = "1" ] || echo -n "Disabling radios:" for dev in bluetooth nfc wifi wwan; do if wordinlist "$dev" "$devs2disable"; then [ "$quiet" = "1" ] || printf ' %s' "$dev" device_switch $dev off fi done [ "$quiet" = "1" ] || echo "." fi # enable configured radios if [ -n "$devs2enable" ]; then if [ "$1" = "radiosw" ]; then # radiosw mode: disable radios not listed for dev in bluetooth nfc wifi wwan; do if ! wordinlist "$dev" "$devs2enable"; then device_switch $dev off fi done else # start mode: enable listed radios [ "$quiet" = "1" ] || echo -n "Enabling radios:" for dev in bluetooth nfc wifi wwan; do if wordinlist "$dev" "$devs2enable"; then [ "$quiet" = "1" ] || printf ' %s' "$dev" device_switch $dev on fi done [ "$quiet" = "1" ] || echo "." fi fi # clean up: discard state file rm -f "$RFSTATEFILE" 2> /dev/null fi return 0 } ukui-power-manager/3rd/tlp/func.d/40-tlp-func-bay0000664000175000017500000001431115167661430020341 0ustar fengfeng#!/bin/sh # tlp-func-bay - Bay Functions # # Copyright (c) 2024 Thomas Koch and others. # This software is licensed under the GPL v2 or later. # SPDX-License-Identifier: GPL-2.0-or-later # ---------------------------------------------------------------------------- # Constants readonly DOCKGLOB="/sys/devices/platform/dock.?" readonly BAYSTATEFILE=$RUNDIR/bay_saved # ---------------------------------------------------------------------------- # Functions # --- Drive Bay get_drivebay_device () { # Find generic dock interface for drive bay # rc: 0; retval: $dock dock=$(grep -l 'ata_bay' "$DOCKGLOB/type" 2> /dev/null) dock=${dock%%/type} if [ ! -d "$dock" ]; then dock="" fi return 0 } check_is_docked() { # check if $dock is docked; # rc: 0 if docked, else 1 local dock_status dock_info_file # return 0 if any sysfs file indicates "docked" for dock_info_file in docked firmware_node/status; do if [ -f "$dock/$dock_info_file" ] && \ read -r dock_status < "$dock/$dock_info_file" 2>/dev/null; then # catch empty $dock_status (safety check, unlikely case) [ "${dock_status:-0}" != "0" ] && return 0 fi done # otherwise assume "not docked" return 1 } poweroff_drivebay () { # power off optical drive in drive bay # $1: 0=ac mode, 1=battery mode # $2: 0=conditional+quiet mode, 1=force+verbose mode # Some code adapted from https://www.thinkwiki.org/wiki/How_to_hotswap_UltraBay_devices local pwr optdrv syspath if [ "$1" = "1" ]; then pwr="$BAY_POWEROFF_ON_BAT" else pwr="$BAY_POWEROFF_ON_AC" fi # Run only if forced or enabled if [ "$2" != "1" ]; then case "$pwr" in 1) # enabled --> proceed ;; 0) # disabled echo_debug "pm" "poweroff_drivebay($1).disabled" return 0 ;; *) # not configured or invalid parameter echo_debug "pm" "poweroff_drivebay($1).not_configured" return 0 ;; esac fi get_drivebay_device if [ -z "$dock" ] || [ ! -d "$dock" ]; then echo_debug "pm" "poweroff_drivebay($1).no_bay_device" [ "$2" = "1" ] && echo "Error: cannot locate bay device." 1>&2 return 1 fi echo_debug "pm" "poweroff_drivebay($1): dock=$dock" # Check if bay is occupied if ! check_is_docked; then echo_debug "pm" "poweroff_drivebay($1).drive_already_off" [ "$2" = "1" ] && echo "No drive in bay (or power already off)." else # Check for optical drive optdrv="$BAY_DEVICE" if [ -z "$optdrv" ]; then echo_debug "pm" "poweroff_drivebay($1).opt_drive_not_configured" [ "$2" = "1" ] && echo "Error: no optical drive configured (BAY_DEVICE=\"\")." 1>&2 return 1 elif [ ! -b "/dev/$optdrv" ]; then echo_debug "pm" "poweroff_drivebay($1).no_opt_drive: /dev/$optdrv" [ "$2" = "1" ] && echo "No optical drive in bay (/dev/$optdrv)." return 0 else echo_debug "pm" "poweroff_drivebay($1): optdrv=$optdrv" [ "$2" = "1" ] && echo -n "Powering off drive bay..." # Unmount media umount -l "$optdrv" > /dev/null 2>&1 # Sync drive sync sleep 1 # Power off drive $HDPARM -Y "$optdrv" > /dev/null 2>&1 sleep 5 # Unregister scsi device if syspath="$($UDEVADM info --query=path --name="$optdrv" 2> /dev/null)"; then syspath="/sys${syspath%/block/*}" if [ "$syspath" != "/sys" ]; then write_sysf "1" "$syspath/delete" echo_debug "pm" "poweroff_drivebay($1): syspath=$syspath; rc=$?" else echo_debug "pm" "poweroff_drivebay($1): got empty/invalid syspath for $optdrv" fi else echo_debug "pm" "poweroff_drivebay($1): failed to get syspath (udevadm returned $?)" fi # Turn power off write_sysf "1" "$dock/undock" echo_debug "pm" "poweroff_drivebay($1).bay_powered_off: rc=$?" [ "$2" = "1" ] && echo "done." fi fi return 0 } suspend_drivebay () { # Save power state of drive bay before suspend # $1: 0=ac mode, 1=battery mode if [ "$1" = "1" ] && [ "$BAY_POWEROFF_ON_BAT" = "1" ] || \ [ "$1" = "0" ] && [ "$BAY_POWEROFF_ON_AC" = "1" ]; then # setting corresponding to mode is active -> save state get_drivebay_device if [ -n "$dock" ]; then create_rundir if ! check_is_docked; then write_sysf "off" "$BAYSTATEFILE" echo_debug "pm" "suspend_drivebay($1): bay=off; rc=$?" else write_sysf "on" "$BAYSTATEFILE" echo_debug "pm" "suspend_drivebay($1): bay=on; rc=$?" fi fi else # setting not active -> remove state file rm -f "$BAYSTATEFILE" 2> /dev/null fi return 0 } resume_drivebay () { # # $1: 0=ac mode, 1=battery mode local cnt rc if [ "$(read_sysf "$BAYSTATEFILE")" = "off" ]; then # saved state = off get_drivebay_device if [ -n "$dock" ]; then if check_is_docked; then # device active -> deactivate if [ -e "$dock/undock" ]; then cnt=5 rc=1 until [ $rc = 0 ] || [ $cnt = 0 ]; do cnt=$((cnt - 1)) { printf '%s\n' "1" > "$dock/undock"; } 2> /dev/null rc=$? [ $rc = 0 ] || sleep 0.5 done echo_debug "pm" "resume_drivebay.bay_off: rc=$rc" fi else echo_debug "pm" "resume_drivebay.already_off" fi fi else # No saved state or state != off --> apply settings poweroff_drivebay "$1" 0 fi rm -f "$BAYSTATEFILE" 2> /dev/null return 0 } ukui-power-manager/3rd/tlp/func.d/tlp-func-stat0000664000175000017500000006265515167661430020336 0ustar fengfeng#!/bin/sh # tlp-func-stat - tlp-stat Helper Functions # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 15-tlp-func-disk, 35-tlp-func-batt # ---------------------------------------------------------------------------- # Constants readonly INITCTL=initctl readonly SESTATUS=sestatus readonly SMARTCTL=smartctl readonly RE_AC_QUIRK='^UNDEFINED$' readonly RE_ATA_ERROR='ata[0-9]+: SError: {.*CommWake }' # ---------------------------------------------------------------------------- # Functions # --- Checks check_upstart () { # check if upstart is active init system (PID 1) # rc: 0=yes, 1=no cmd_exists $INITCTL && $INITCTL --version | grep -q upstart } check_openrc () { # check if openrc is the active init system (PID 1) # rc: 0=yes, 1=no [ -e /run/openrc/softlevel ] } check_ac_quirk () { # check for hardware known not to expose AC device # $1: model string; rc: 0=yes, 1=no printf '%s' "$1" | grep -E -q "${RE_AC_QUIRK}" } # --- Formatted Output printparm () { # formatted output of sysfile - general # $1: format, $2: sysfile, $3: n/a message, $4: cutoff local format="$1" local sysf="$2" local namsg="$3" local cutoff="$4" local val="" if val=$(read_sysf "$sysf"); then # sysfile read successful if [ -n "$cutoff" ]; then val=${val%"$cutoff"} fi fi if [ -z "$val" ]; then # replace empty value with n/a text if [ -n "$namsg" ]; then if [ "$namsg" != "_" ]; then # use specific n/a text format=$(echo "$format" | sed -r -e "s/##(.*)##/($namsg)/" -e "s/\[.*\]//") else # _ = skip sysf="" fi else # empty n/a text, use default text format=$(echo "$format" | sed -r -e "s/##(.*)##/(not available)/" -e "s/\[.*\]//") fi # output n/a text or skip # shellcheck disable=SC2059 [ -n "$sysf" ] && printf "$format\n" "$sysf" else # non empty value: strip delimiters from format str format=$(echo "$format" | sed -r "s/##(.*)##/\1/") # shellcheck disable=SC2059 printf "$format\n" "$sysf" "$val" fi return 0 } printparm_epb () { # formatted output of sysfile - Intel EPB variant # $1: sysfile local val strval if val=$(read_sysf "$1"); then # sysfile exists and is actually readable, output content printf "%-54s = %2d " "$1" "$val" # Convert distinct values to strings strval=$(echo "$val" | sed -r 's/^0/performance/; s/^4/balance_performance/; s/^6/default/; s/^8/balance_power/; s/^15/power/; s/[0-9]+//') if [ -n "$strval" ]; then printf "(%s) [EPB]\n" "$strval" else printf " [EPB]\n" fi else # sysfile was not readable printf "%-54s = (not available) [EPB]\n" "$1" fi return 0 } printparm_ml () { # indented output of a multiline sysfile # $1: indent str, $2: sysfile, $3: n/a message local ind="$1" local sysf="$2" local namsg="$3" local sline if [ -f "$sysf" ]; then printf "%s:\n" "$sysf" # read and output sysfile line by line # shellcheck disable=SC2162 while read -r sline; do printf "%s%s\n" "$ind" "$sline" done < "$sysf" printf "\n" elif [ -n "$namsg" ]; then printf "%s (%s)\n\n" "$sysf" "$namsg" fi } print_sysf () { # formatted output of a sysfile # $1: format; $2: sysfile local val if val=$(read_sysf "$2"); then # sysfile readable # shellcheck disable=SC2059 printf "$1" "$val" else # sysfile not readable # shellcheck disable=SC2059 printf "$1" "(not available)" fi return 0 } print_sysf_trim () { # formatted output of a sysfile, trim leading and trailing # blanks -- $1: format; $2: sysfile local val if val=$(read_sysf "$2"); then # sysfile readable # shellcheck disable=SC2059 printf "$1" "$(printf "%s" "$val" | sed -r 's/^[[:blank:]]*//;s/[[:blank:]]*$//')" else # sysfile not readable # shellcheck disable=SC2059 printf "$1" "(not available)" fi return 0 } print_file_modtime_and_age () { # show a file's last modification time # and age in secs -- $1: file local mtime age if [ -f "$1" ]; then mtime=$(date +%X -r "$1") age=$(( $(date +%s) - $(date +%s -r "$1") )) printf '%s, %d sec(s) ago' "$mtime" "$age" else printf "unknown" fi } print_saved_powerstate () { # read and print saved state local sps sps="$(read_sysf "$PWRRUNFILE")" case "$sps" in 0) printf "AC" ;; 1) printf "battery" ;; *) printf "unknown" ;; esac # check for manual mode get_manual_mode # shellcheck disable=SC2154 case "$_manual_mode" in 0|1|a) printf " (manual)\n" ;; n) # check for persistent mode # shellcheck disable=SC2154 if get_persist_mode && [ "$_persist_mode" = "$sps" ]; then printf " (persistent)\n" else printf "\n" fi ;; esac return 0 } print_selinux () { # print SELinux status and mode if cmd_exists $SESTATUS; then $SESTATUS | awk -F '[ \t\n]+' '/SELinux status:/ { printf "SELinux status = %s", $3 } ; \ /Current mode:/ { printf " (%s)", $3 }' printf "\n" fi } # --- Storage Devices print_disk_model () { # print disk model -- $1: dev local model vendor model=$($HDPARM -I "/dev/$1" 2> /dev/null | grep 'Model Number' | \ cut -f2 -d: | sed -r 's/^ *//' ) if [ -z "$model" ]; then # hdparm -I not supported --> try udevadm approach vendor="$($UDEVADM info -q property "/dev/$1" 2>/dev/null | sed -n 's/^ID_VENDOR=//p')" model="$( $UDEVADM info -q property "/dev/$1" 2>/dev/null | sed -n 's/^ID_MODEL=//p' )" model=$(printf "%s %s" "$vendor" "$model" | sed -r 's/_/ /g; s/-//g; s/[[:space:]]+$//') fi printf '%s\n' "${model:-unknown}" return 0 } print_disk_firmware () { # print firmware version --- $1: dev local firmware firmware=$($HDPARM -I "/dev/$1" 2> /dev/null | grep 'Firmware Revision' | \ cut -f2 -d: | sed -r 's/^ *//' ) printf '%s\n' "${firmware:-unknown}" return 0 } get_disk_state () { # get disk power state -- $1: dev; retval: $_disk_state _disk_state=$($HDPARM -C "/dev/$1" 2> /dev/null | awk -F ':' '/drive state is/ { gsub(/ /,"",$2); print $2; }') [ -z "$_disk_state" ] && _disk_state="(not available)" return 0 } get_disk_apm_level () { # get disk apm level -- $1: dev; rc: apm local apm apm=$($HDPARM -I "/dev/$1" 2> /dev/null | grep 'Advanced power management level' | \ cut -f2 -d: | grep -E '^ *[0-9]+ *$') if [ -n "$apm" ]; then return "$apm" else return 0 fi } get_disk_trim_capability () { # check for trim capability # $1: dev; rc: 0=no, 1=yes, 254=no ssd device local trim if $HDPARM -I "/dev/$1" 2> /dev/null | grep -q 'Solid State Device'; then if $HDPARM -I "/dev/$1" 2> /dev/null | grep -q 'TRIM supported'; then trim=1 else trim=0 fi else trim=255 fi return $trim } check_ata_errors () { # check kernel log for ata errors # (possibly) caused by SATA_LINKPWR_ON_AC/BAT != max_performance # stdout: error count for lpw in $SATA_LINKPWR_ON_BAT $SATA_LINKPWR_ON_AC; do if wordinlist "$lpw" "min_power med_power_with_dipm medium_power"; then # config values != max_performance exist --> check kernel log # count matching error lines and quit dmesg | grep -E -c "${RE_ATA_ERROR}" 2> /dev/null return 0 fi done # no values in question configured echo "0" return 0 } get_ahci_host () { # get host associated with a disk # $1: device # retval: $_ahci_host # /sys/block/$device is a softlink to # ../devices/pci0000:00/0000:00:XY.Z/ataN/.../$device # which reveals the associated ahci host: 0000:00:XY.Z/ataN/hostM _ahci_host="$(readlink "/sys/block/$1" | sed -r 's/^\.\.\/devices\/pci[0-9:]+\/[0-9a-f:.]+\/ata[0-9]+\/(host[0-9]+).*$/\1/')" if [ -n "$_ahci_host" ]; then echo_debug "disk" "get_ahci_host($1): host=$_ahci_host" return 0 else echo_debug "disk" "get_ahci_host($1).none" return 1 fi } print_nvme_temp () { # print NVMe disk temperature from hwmon API # $1: device # # Reference: # - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=400b6a7b13a3fd71cff087139ce45dd1e5fff444 local sens ts # temp1_input is "Composite" for sens in $(glob_files '/hwmon*/temp1_input' "/sys/block/$1/device"); do if ts=$(read_sysval "$sens"); then perl -e 'printf (" Temp = %-2.0f °C\n", '"$ts"' / 1000.0);' break fi done return 0 } anonymize_disk_id () { # replace disk serial number with asterisks # $1: disk id if [ "$1" = "${1%_*}" ]; then printf "%s" "$1" else echo "$1" | \ awk '{ s = $1 i = length(s) while (substr(s, i, 1) != "_" && i > 0) { s = substr(s, 1, i-1) "*" substr(s, i+1) i-- } print s }' fi } show_disk_data () { # formatted output of NVMe / SATA disk data # $1: disk device # translate disk name and check presence if ! get_disk_dev "$1"; then # no block device for disk name --> we're done # shellcheck disable=SC2154 printf "\n%s: not present.\n" "/dev/$_disk_dev" return 1 fi # --- show general data # shellcheck disable=SC2154 case "$_disk_type" in nvme) # NVMe disk printf "\n%s:\n" "/dev/$_disk_dev" printf " Type = NVMe\n" [ -n "$_disk_id" ] && printf " Disk ID = %s\n" "$(anonymize_disk_id "$_disk_id")" print_sysf " Model = %s\n" "/sys/block/$_disk_dev/device/model" print_sysf " Firmware = %s\n" "/sys/block/$_disk_dev/device/firmware_rev" print_nvme_temp "$_disk_dev" ;; sata|ata|usb|ieee1394) # ATA/USB/IEEE1394 disk printf "\n%s:\n" "/dev/$_disk_dev" printf " Type = %s\n" "$(toupper "$_disk_type")" [ -n "$_disk_id" ] && printf " Disk ID = %s\n" "$(anonymize_disk_id "$_disk_id")" # save spindle state get_disk_state "$_disk_dev" printf " Model = " print_disk_model "$_disk_dev" printf " Firmware = " print_disk_firmware "$_disk_dev" get_disk_apm_level "$_disk_dev"; local apm=$? printf " APM Level = " case $apm in 0|255) printf "none/disabled\n" ;; *) printf "%s" $apm if wordinlist "$_disk_type" "$DISK_TYPES_NO_APM_CHANGE"; then printf " (changes not supported)\n" else printf "\n" fi ;; esac printf " Status = %s\n" "$_disk_state" get_disk_trim_capability "$_disk_dev"; local trim=$? case $trim in 0) printf " TRIM = not supported\n" ;; 1) printf " TRIM = supported\n" ;; esac if [ "$_disk_type" = "sata" ] || [ "$_disk_type" = "ata" ]; then get_ahci_host "$_disk_dev" && printf " Host = %s\n" "$_ahci_host" fi # restore standby state [ "$_disk_state" = "standby" ] && spindown_disk "$_disk_dev" ;; *) printf "\n%s: Device type \"%s\" ignored.\n" "/dev/$_disk_dev" "$_disk_type" return 1 ;; esac if [ -f "/sys/block/$_disk_dev/queue/scheduler" ]; then # shellcheck disable=SC2154 if [ "$_disk_mq" = "1" ]; then print_sysf_trim " Scheduler = %s (multi queue)\n" "/sys/block/$_disk_dev/queue/scheduler" else print_sysf_trim " Scheduler = %s (single queue)\n" "/sys/block/$_disk_dev/queue/scheduler" fi fi # shellcheck disable=SC2154 if [ "$_disk_runpm" != "3" ]; then # disk has runtime pm capability echo # shellcheck disable=SC2154 case "$_disk_runpm" in 0) printf " Runtime PM:\n";; 1) printf " Runtime PM: locked by kernel\n";; 2) printf " Runtime PM: locked by TLP\n" ;; esac print_sysf " /sys/block/$_disk_dev/device/power/control = %s, " "/sys/block/$_disk_dev/device/power/control" print_sysf "autosuspend_delay_ms = %s\n" "/sys/block/$_disk_dev/device/power/autosuspend_delay_ms" fi # --- show SMART data # skip if smartctl not installed or disk not SMART capable cmd_exists "$SMARTCTL" && $SMARTCTL "/dev/$_disk_dev" > /dev/null 2>&1 || return 0 case "$_disk_type" in nvme) # NVMe disk printf "\n SMART info:\n" $SMARTCTL -A "/dev/$_disk_dev" | \ grep -E -e '^(Critical Warning|Temperature:|Available Spare)' \ -e '^(Percentage Used:|Data Units Written:|Power|Unsafe)' \ -e 'Integrity Errors' | \ sed 's/^/ /' ;; sata|ata|usb) printf "\n SMART info:\n" $SMARTCTL -A "/dev/$_disk_dev" | grep -v '<==' | \ awk -F ' ' '$2 ~ /Power_Cycle_Count|Start_Stop_Count|Load_Cycle_Count|Reallocated_Sector_Ct/ \ { printf " %3d %-25s = %8d \n", $1, $2, $10 } ; \ $2 ~ /Used_Rsvd_Blk_Cnt_Chip|Used_Rsvd_Blk_Cnt_Tot|Unused_Rsvd_Blk_Cnt_Tot/ \ { printf " %3d %-25s = %8d \n", $1, $2, $10 } ; \ $2 ~ /Power_On_Hours/ \ { printf " %3d %-25s = %8d %s\n", $1, $2, $10, "[h]" } ; \ $2 ~ /Temperature_Celsius/ \ { printf " %3d %-25s = %8d %s %s %s %s\n", $1, $2, $10, $11, $12, $13, "[°C]" } ; \ $2 ~ /Airflow_Temperature_Cel/ \ { printf " %3d %-25s = %8d %s\n", $1, $2, $10, "[°C]" } ; \ $2 ~ /G-Sense_Error_Rate/ \ { printf " %3d %-25s = %8d \n", $1, $2, $10 } ; \ $2 ~ /Host_Writes/ \ { printf " %3d %-25s = %8.3f %s\n", $1, $2, $10 / 32768.0, "[TB]" } ; \ $2 ~ /Total_LBAs_Written/ \ { printf " %3d %-25s = %8.3f %s\n", $1, $2, $10 / 2147483648.0, "[TB]" } ; \ $2 ~ /NAND_Writes_1GiB/ \ { printf " %3d %-25s = %8d %s\n", $1, $2, $10, "[GB]" } ; \ $2 ~ /Available_Reservd_Space|Media_Wearout_Indicator|Wear_Leveling_Count/ \ { printf " %3d %-25s = %8d %s\n", $1, $2, $4, "[%]" }' ;; *) # unknown disk type ;; esac return 0 } get_ahci_disk () { # get disk associated with an alpm or ahci port runtime pm sysfile # $1: sysfile # retval: $_ahci_disk local aport # cut sysfile path down to the ahci port /sys/bus/pci/devices/0000:00:XY.Z/ataN aport="$(echo "$1" | sed -r 's/^(\/sys\/bus\/pci\/devices\/[0-9a-f:.]+\/ata[0-9]+).*$/\1/')" # the directory /sys/bus/pci/devices/0000:00:XY.Z/ataN/host*/target*/*/block # lists the actual block device name pointing to /dev/sdX resp. /sys/block/sdX # shellcheck disable=SC2086 _ahci_disk="$(glob_dirs '/*' ${aport}/host*/target*/*/block 2> /dev/null | head -1)" _ahci_disk="${_ahci_disk##/*/}" if [ -n "$_ahci_disk" ]; then echo_debug "disk" "get_ahci_disk($1): port=$aport ahci_disk=$_ahci_disk" return 0 else echo_debug "disk" "get_ahci_disk($1).none" return 1 fi } printparm_ahci () { # print alpm or ahci port runtime pm sysfile # accompanied by the attached disk device # $1: sysfile local val if val=$(read_sysf "$1"); then # sysfile exists and is actually readable, output content printf "%-56s = %s " "$1" "$val" get_ahci_disk "$1" if [ -n "$_ahci_disk" ]; then printf " -- %s\n" "$_ahci_disk" else printf "\n" fi fi return 0 } # --- Graphics printparm_i915 () { # formatted output of sysfile - i915 kernel module variant # $*: sysfile alternatives local sysf val for sysf in "$@"; do if val=$(read_sysf "$sysf"); then # sysfile exists and is actually readable, output content printf "%-44s = %2d " "$sysf" "$val" # explain content if [ "$val" = "-1" ]; then printf "(use per-chip default)\n" else printf "(" if [ "${sysf##/*/}" = "enable_psr" ]; then # enable_psr case $val in 0) printf "disabled" ;; 1) printf "enabled" ;; 2) printf "force link-standby mode" ;; 3) printf "force link-off mode" ;; *) printf "unknown" ;; esac else # other parms if [ $((val & 1)) -ne 0 ]; then printf "enabled" else printf "disabled" fi [ $((val & 2)) -ne 0 ] && printf " + deep" [ $((val & 4)) -ne 0 ] && printf " + deepest" fi printf ")\n" fi # print first match only break fi done return 0 } show_gpu_data () { # show GPU data for all drivers local driver gpu sysout local hdr= for gpu in "${BASE_DRMD}"/card?; do [ -d "$gpu" ] || continue driver=$(readlink "${gpu}/device/driver") driver=${driver##*/} case "$driver" in i915*) # Intel GPU get_intel_gpu_sysdirs "$gpu" "$driver" # power managment data if [ "$hdr" != "i915" ]; then printf "+++ Intel Graphics\n" hdr="i915" fi printf "%-44s = %s\n\n" "$gpu/device/driver" "$driver" # shellcheck disable=SC2154 printparm_i915 "$gpu/power/rc6_enable" "$_intel_gpu_parm/enable_rc6" "$_intel_gpu_parm/i915_enable_rc6" # shellcheck disable=SC2154 if sysout=$(grep '^FBC ' "$_intel_gpu_dbg/i915_fbc_status" 2> /dev/null); then printf "%-44s = %s\n" "$_intel_gpu_dbg/i915_fbc_status" "$sysout" else printparm_i915 "$_intel_gpu_parm/enable_fbc" "$_intel_gpu_parm/i915_enable_fbc" fi if sysout=$(grep '^PSR mode:' "$_intel_gpu_dbg/i915_edp_psr_status" 2> /dev/null); then printf "%-44s = %s\n" "$_intel_gpu_dbg/i915_edp_psr_status" "$sysout" else printparm_i915 "$_intel_gpu_parm/enable_psr" fi printf "\n" # frequency parameters if readable_sysf "$gpu/$IGPU_MIN_FREQ"; then printparm "%-44s = ##%5d## [MHz]" "$gpu/$IGPU_MIN_FREQ" printparm "%-44s = ##%5d## [MHz]" "$gpu/$IGPU_MAX_FREQ" printparm "%-44s = ##%5d## [MHz]" "$gpu/$IGPU_BOOST_FREQ" printparm "%-44s = ##%5d## [MHz] (GPU min)" "$gpu/$IGPU_RPN_FREQ" printparm "%-44s = ##%5d## [MHz] (GPU max)" "$gpu/$IGPU_RP0_FREQ" printf "\n" fi ;; amdgpu) # AMD GPU if [ "$hdr" != "amdgpu" ]; then printf "+++ AMD Radeon Graphics\n" hdr="amdgpu" fi printf "%-65s = %s\n\n" "$gpu/device/driver" "$driver" if [ -f "$gpu/device/power_dpm_force_performance_level" ]; then printparm "%-65s = ##%s##" "$gpu/device/power_dpm_force_performance_level" printf "\n" fi ;; radeon) # AMD GPU if [ "$hdr" != "radeon" ]; then printf "+++ AMD Radeon Graphics\n" hdr="radeon" fi printf "%-65s = %s\n\n" "$gpu/device/driver" "$driver" if [ -f "$gpu/device/power_dpm_force_performance_level" ]; then # AMD hardware printparm "%-65s = ##%s##" "$gpu/device/power_dpm_force_performance_level" printparm "%-65s = ##%s##" "$gpu/device/power_dpm_state" printf "\n" elif [ -f "$gpu/device/power_method" ]; then # legacy ATI hardware printparm "%-65s = ##%s##" "$gpu/device/power_method" printparm "%-65s = ##%s##" "$gpu/device/power_profile" printf "\n" fi ;; nouveau|nvidia) # Nvidia GPU if [ "$hdr" != "$driver" ]; then printf "+++ Nvidia Graphics\n" hdr="$driver" fi printf "%-44s = %s\n\n" "$gpu/device/driver" "$driver" ;; *) # Other GPU if [ "$hdr" != "$driver" ]; then printf "+++ Other Graphics\n" hdr="$driver" fi printf "%-44s = %s\n\n" "$gpu/device/driver" "$driver" ;; esac done return 0 } # --- Battery print_methods_per_driver () { # show features provided by a Thinkpad battery plugin # $1: driver = natacpi, tpacpi, tpsmapi local bm m mlist="" for bm in _bm_read _bm_thresh _bm_dischg; do if [ "$(eval echo \$$bm)" = "$1" ]; then # method matches driver m="" case $bm in _bm_read) [ "$1" = "tpsmapi" ] && m="status" ;; _bm_thresh) m="charge thresholds" ;; _bm_dischg) m="recalibration" ;; esac if [ -n "$m" ]; then # concat method to output [ -n "$mlist" ] && mlist="${mlist}, " mlist="${mlist}${m}" fi fi done if [ -n "$mlist" ]; then printf "(%s)\n" "$mlist" else printf "(none)\n" fi return 0 } print_batstate () { # print battery charging state with # an explanation when a threshold inhibits charging # $1: sysfile # global params: $_bm_thresh, $_syspwr local sysf val # check if bat state sysfile exists if [ -f "$1" ]; then sysf=$1 else # sysfile non-existent printf "%-59s = (not available)\n" "$1" return 0 fi if val=$(read_sysf "$sysf"); then # sysfile was readable, output state # map "Unknown" to "Idle" for clarity (and avoid user questions) [ "$val" = "Unknown" ] && val="Idle" printf "%-59s = %s\n" "$sysf" "$val" else # sysfile was not readable printf "%-59s = (not available)\n" "$sysf" fi return 0 } print_battery_cycle_count () { # print battery cycle count, explain special case of 0 # $1: sysfile # $2: cycle count case "$2" in 0) printf "%-59s = %6d (or not supported)\n" "$1" "$2" ;; "") printf "%-59s = (not supported)\n" "$1" ;; *) printf "%-59s = %6d\n" "$1" "$2" ;; esac return 0 } # -- udev diagnostic check_udev_rule_ps () { # check if udev rule for power source changes draws if [ -n "$_psdev" ]; then $UDEVADM test -a change "$_psdev" 2>&1 | grep -E '^Reading rules file: .*tlp.rules$' if $UDEVADM test -a change "$_psdev" 2> /dev/null | grep -E '^run: .*tlp auto'; then printf "OK.\n\n" else printf "Fatal Error: TLP's udev rule for power source changes (85-tlp.rules) is not active -- possible package bug.\n\n" fi fi } check_udev_rule_usb () { # check if udev rule for connecting USB device draws local ud ud="$(glob_dirs '/*' /sys/bus/usb/devices 2> /dev/null | grep -v ':' | head -1)" if [ -n "$ud" ]; then $UDEVADM test -a add "$ud" 2>&1 | grep -E '^Reading rules file: .*tlp.rules$' if $UDEVADM test -a add "$ud" 2> /dev/null | grep -E '^run: .*tlp-usb-udev usb'; then printf "OK.\n\n" else printf "Fatal Error: TLP's udev rule for connecting USB devices (85-tlp.rules) is not active -- possible package bug.\n\n" fi fi } ukui-power-manager/3rd/tlp/func.d/10-tlp-func-cpu0000664000175000017500000004306015167661430020355 0ustar fengfeng#!/bin/sh # tlp-func-cpu - Processor Functions # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base # ---------------------------------------------------------------------------- # Constants readonly CPUD=/sys/devices/system/cpu readonly CPU_BOOST_ALL_CTRL=${CPUD}/cpufreq/boost readonly INTEL_PSTATED=${CPUD}/intel_pstate readonly AMD_PSTATED=${CPUD}/amd_pstate readonly CPU_MIN_PERF_PCT=$INTEL_PSTATED/min_perf_pct readonly CPU_MAX_PERF_PCT=$INTEL_PSTATED/max_perf_pct readonly CPU_TURBO_PSTATE=$INTEL_PSTATED/no_turbo readonly INTEL_DYN_BOOST=$INTEL_PSTATED/hwp_dynamic_boost readonly AMD_DYN_BOOST=$AMD_PSTATED/cppc_dynamic_boost readonly CPU_INFO=/proc/cpuinfo readonly ENERGYPERF=x86_energy_perf_policy readonly FWACPID=/sys/firmware/acpi # ---------------------------------------------------------------------------- # Functions # --- Scaling Driver and Governor check_intel_pstate () { # detect intel_pstate driver -- rc: 0=present/1=absent # note: intel_pstate requires Linux 3.9 or higher [ -d $INTEL_PSTATED ] } check_amd_pstate () { # detect amd_pstate driver -- rc: 0=present/1=absent # note: intel_pstate requires Linux 5.17 or higher [ -d $AMD_PSTATED ] } print_cpu_driver () { # print active CPU scaling driver read_sysf "${CPUD}/cpu0/cpufreq/scaling_driver" || printf "cpu" } set_cpu_driver_opmode () { # set CPU driver operation mode -- $1: 0=ac mode, 1=battery mode local cfg opmode if [ "$1" = "1" ]; then opmode=${CPU_DRIVER_OPMODE_ON_BAT:-} cfg="CPU_DRIVER_OPMODE_ON_BAT" else opmode=${CPU_DRIVER_OPMODE_ON_AC:-} cfg="CPU_DRIVER_OPMODE_ON_AC" fi if [ -z "$opmode" ]; then echo_debug "pm" "set_cpu_driver_opmode($1).not_configured" return 0 fi if check_intel_pstate; then if write_sysf "$opmode" "${INTEL_PSTATED}/status"; then echo_debug "pm" "set_cpu_driver_opmode($1).intel_pstate: $opmode; rc=$?" else # kernel rejected the configured opmode echo_debug "pm" "set_cpu_driver_opmode($1).intel_pstate: $opmode; rc=$?" echo_message "Error in configuration at ${cfg}=\"${opmode}\": this operation mode is not supported by the intel_pstate driver." return 1 fi elif check_amd_pstate; then if write_sysf "$opmode" "${AMD_PSTATED}/status"; then echo_debug "pm" "set_cpu_driver_opmode($1).amd_pstate: $opmode; rc=$?" else # kernel rejected the configured opmode echo_debug "pm" "set_cpu_driver_opmode($1).amd_pstate: $opmode; rc=$?" echo_message "Error in configuration at ${cfg}=\"${opmode}\": this operation mode is not supported by the amd-pstate driver." return 1 fi else echo_debug "pm" "set_cpu_driver_opmode($1).unsupported_driver" echo_message "Error in configuration at ${cfg}=\"${opmode}\": the $(print_cpu_driver) driver does not support operation modes." return 1 fi return 0 } set_cpu_scaling_governor () { # set CPU scaling governor -- $1: 0=ac mode, 1=battery mode local cfg cpu ec gov if [ "$1" = "1" ]; then gov=${CPU_SCALING_GOVERNOR_ON_BAT:-} cfg="CPU_SCALING_GOVERNOR_ON_BAT" else gov=${CPU_SCALING_GOVERNOR_ON_AC:-} cfg="CPU_SCALING_GOVERNOR_ON_AC" fi if [ -n "$gov" ]; then # apply governor ec=0 for cpu in "${CPUD}"/cpu*/cpufreq/scaling_governor; do if [ -f "$cpu" ] && ! write_sysf "$gov" "$cpu"; then echo_debug "pm" "set_cpu_scaling_governor($1).write_error: $cpu $gov; rc=$?" ec=$((ec+1)) fi done if [ "$ec" -gt 0 ]; then # kernel rejected the configured governor echo_debug "pm" "set_cpu_scaling_governor($1).not_available: $gov; ec=$ec" echo_message "Error in configuration at ${cfg}=\"${gov}\": governor not available." return 1 fi echo_debug "pm" "set_cpu_scaling_governor($1): $gov; ec=$ec" else echo_debug "pm" "set_cpu_scaling_governor($1).not_configured" fi return 0 } set_cpu_scaling_min_max_freq () { # set CPU scaling limits -- $1: 0=ac mode, 1=battery mode local minfreq maxfreq cpu ec local conf=0 if [ "$1" = "1" ]; then minfreq=${CPU_SCALING_MIN_FREQ_ON_BAT:-} maxfreq=${CPU_SCALING_MAX_FREQ_ON_BAT:-} else minfreq=${CPU_SCALING_MIN_FREQ_ON_AC:-} maxfreq=${CPU_SCALING_MAX_FREQ_ON_AC:-} fi if [ -n "$minfreq" ] && [ "$minfreq" != "0" ]; then conf=1 ec=0 for cpu in "${CPUD}"/cpu*/cpufreq/scaling_min_freq; do if [ -f "$cpu" ] && ! write_sysf "$minfreq" "$cpu"; then echo_debug "pm" "set_cpu_scaling_min_max_freq($1).min.write_error: $cpu $minfreq; rc=$?" ec=$((ec+1)) fi done echo_debug "pm" "set_cpu_scaling_min_max_freq($1).min: $minfreq; ec=$ec" fi if [ -n "$maxfreq" ] && [ "$maxfreq" != "0" ]; then conf=1 ec=0 for cpu in "${CPUD}"/cpu*/cpufreq/scaling_max_freq; do if [ -f "$cpu" ] && ! write_sysf "$maxfreq" "$cpu"; then echo_debug "pm" "set_cpu_scaling_min_max_freq($1).max.write_error: $cpu $maxfreq; rc=$?" ec=$((ec+1)) fi done echo_debug "pm" "set_cpu_scaling_min_max_freq($1).max: $maxfreq; ec=$ec" fi [ $conf -eq 1 ] || echo_debug "pm" "set_cpu_scaling_min_max_freq($1).not_configured" return 0 } # --- Performance Policies and Boost supports_intel_cpu_epb () { # rc: 0=CPU supports EPB/1=false grep -E -q -m 1 '^flags.+epb' $CPU_INFO } supports_intel_cpu_epp () { # rc: 0=CPU supports HWP.EPP/1=false grep -E -q -m 1 '^flags.+hwp_epp' $CPU_INFO } supports_amd_cpu_epp () { # rc: 0=CPU supports amd_pstate EPP/1=false [ "$(read_sysf "${AMD_PSTATED}/status")" = "active" ] } set_cpu_perf_policy () { # set Intel/AMD CPU energy vs. performance policies # $1: 0=ac mode, 1=battery mode # # depending on the CPU model the values # performance, balance_performance, default, balance_power, power # in CPU_ENERGY_PERF_POLICY_ON_AC/BAT are applied to: # --- intel_pstate # (a) energy-performance preference (EPP) in IA32_HWP_REQUEST MSR # (b) energy-performance bias (EPB) in IA32_ENERGY_PERF_BIAS MSR # EPP and EPB are mutually exclusive: when EPP is available, # Intel CPUs will not honor EPB # --- amd_pstate # CPPC firmware via the Energy Performance Preference register # Note: needs a patchset not yet merged as of Linux 6.1, see [5] # # References: # [1] https://www.kernel.org/doc/html/latest/admin-guide/pm/intel_pstate.html#energy-vs-performance-hints # [2] https://www.kernel.org/doc/html/latest/admin-guide/pm/intel_epb.html # [3] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4beec1d7519691b4b6c6b764e75b4e694a09c5f7 # [4] http://manpages.ubuntu.com/manpages/kinetic/man8/x86_energy_perf_policy.8.html # [5] https://lore.kernel.org/lkml/20221208111852.386731-1-perry.yuan@amd.com/ local cnt cpuf ec perf pnum if [ "$1" = "1" ]; then perf=${CPU_ENERGY_PERF_POLICY_ON_BAT:-} else perf=${CPU_ENERGY_PERF_POLICY_ON_AC:-} fi # translate alphanumeric values from EPB to EPP syntax case "$perf" in 'balance-performance') perf='balance_performance' ;; 'normal') perf='default' ;; 'balance-power') perf='balance_power' ;; 'powersave') perf='power' ;; esac if [ -z "$perf" ]; then echo_debug "pm" "set_cpu_perf_policy($1).not_configured" return 0 fi if { check_intel_pstate && supports_intel_cpu_epp; } || { check_amd_pstate && supports_amd_cpu_epp; }; then # validate EPP setting case "$perf" in performance|balance_performance|default|balance_power|power) # OK --> continue ;; [0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) # HWP.EPP accepts 0 to 255 --> continue ;; *) # invalid setting echo_debug "pm" "set_cpu_perf_policy($1).epp.invalid: perf=$perf" return 0 ;; esac # don't apply intel_pstate HWP.EPP when power-profile-daemon is running if check_intel_pstate && check_ppd_active ; then echo_message "Warning: CPU_ENERGY_PERF_POLICY_ON_AC/BAT is not set because power-profiles-daemon is running." echo_debug "pm" "set_cpu_perf_policy($1).epp.nop_ppd_active" return 0 fi # apply EPP setting cnt=0 ec=0 for cpuf in "${CPUD}"/cpu*/cpufreq/energy_performance_preference; do if [ -f "$cpuf" ]; then cnt=$((cnt+1)) if ! write_sysf "$perf" "$cpuf"; then echo_debug "pm" "set_cpu_perf_policy($1).epp.write_error: $perf $cpuf; rc=$?" ec=$((ec+1)) fi fi done if [ $cnt -gt 0 ]; then echo_debug "pm" "set_cpu_perf_policy($1).epp: $perf; ec=$ec" # EPP active and applied, quit unless EPB is forced [ "$X_FORCE_EPB" = "1" ] || return 0 else echo_debug "pm" "set_cpu_perf_policy($1).epp.not_available" fi else echo_debug "pm" "set_cpu_perf_policy($1).epp.unsupported_cpu" fi if supports_intel_cpu_epb; then # translate Intel HWP.EPP alphanumeric to EPB numeric values for native kernel support # and x86_energy_perf_policy backwards compatibility; validate numeric values case "$perf" in performance) pnum=0 ;; balance_performance) pnum=4 ;; default) pnum=6 ;; balance_power) pnum=8 ;; power) pnum=15 ;; 0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15) pnum="$perf" ;; *) # invalid setting echo_debug "pm" "set_cpu_perf_policy($1).epb.invalid: perf=$perf" return 0 ;; esac # apply EPB setting # try native kernel API first (5.2 and later) cnt=0 ec=0 for cpuf in "${CPUD}"/cpu*/power/energy_perf_bias; do if [ -f "$cpuf" ]; then cnt=$((cnt + 1)) if ! write_sysf "$pnum" "$cpuf"; then echo_debug "pm" "set_cpu_perf_policy($1).epb_kernel.write_error: $perf($pnum) $cpuf; rc=$?" ec=$((ec+1)) fi fi done if [ $cnt -gt 0 ]; then # native kernel API actually detected echo_debug "pm" "set_cpu_perf_policy($1).epb_kernel: $perf($pnum); ec=$ec" return 0 fi # no native kernel support, try x86_energy_perf_policy if ! cmd_exists $ENERGYPERF; then # x86_energy_perf_policy not installed echo_debug "pm" "set_cpu_perf_policy($1).epb_x: $perf($pnum); x86_energy_perf_policy not installed" else # x86_energy_perf_policy needs kernel module 'msr' load_modules "$MOD_MSR" $ENERGYPERF "$pnum" > /dev/null 2>&1 rc=$? case $rc in 0) echo_debug "pm" "set_cpu_perf_policy($1).epb_x: $perf($pnum); rc=$?" ;; 1) echo_debug "pm" "set_cpu_perf_policy($1).epb_x: $perf($pnum); rc=$? (unsupported cpu)" ;; 2) echo_debug "pm" "set_cpu_perf_policy($1).epb_x: $perf($pnum); rc=$? (kernel specific x86_energy_perf_policy missing)" ;; *) echo_debug "pm" "set_cpu_perf_policy($1).epb_x: $perf($pnum); rc=$? (unknown)" ;; esac return $rc fi else echo_debug "pm" "set_cpu_perf_policy($1).epb.unsupported_cpu" fi return 0 } set_intel_cpu_perf_pct () { # set Intel P-state performance limits # $1: 0=ac mode, 1=battery mode local min max if ! check_intel_pstate; then echo_debug "pm" "set_intel_cpu_perf_pct($1).no_intel_pstate" return 0 fi if [ "$1" = "1" ]; then min=${CPU_MIN_PERF_ON_BAT:-} max=${CPU_MAX_PERF_ON_BAT:-} else min=${CPU_MIN_PERF_ON_AC:-} max=${CPU_MAX_PERF_ON_AC:-} fi if [ ! -f $CPU_MIN_PERF_PCT ]; then echo_debug "pm" "set_intel_cpu_perf_pct($1).min.not_supported" elif [ -n "$min" ]; then write_sysf "$min" $CPU_MIN_PERF_PCT echo_debug "pm" "set_intel_cpu_perf_pct($1).min: $min; rc=$?" else echo_debug "pm" "set_intel_cpu_perf_pct($1).min.not_configured" fi if [ ! -f $CPU_MAX_PERF_PCT ]; then echo_debug "pm" "set_intel_cpu_perf_pct($1).max.not_supported" elif [ -n "$max" ]; then write_sysf "$max" $CPU_MAX_PERF_PCT echo_debug "pm" "set_intel_cpu_perf_pct($1).max: $max; rc=$?" else echo_debug "pm" "set_intel_cpu_perf_pct($1).max.not_configured" fi return 0 } set_cpu_boost_all () { # $1: 0=ac mode, 1=battery mode # global cpu boost behavior control based on the current power mode # # Relevant config option(s): CPU_BOOST_ON_{AC,BAT} with values {'',0,1} # # Note: # * needs commit #615b7300717b9ad5c23d1f391843484fe30f6c12 # (linux-2.6 tree), "Add support for disabling dynamic overclocking", # => requires Linux 3.7 or later local val if [ "$1" = "1" ]; then val=${CPU_BOOST_ON_BAT:-} else val=${CPU_BOOST_ON_AC:-} fi if [ -z "$val" ]; then # do nothing if unconfigured echo_debug "pm" "set_cpu_boost_all($1).not_configured" return 0 fi if check_intel_pstate; then if check_ppd_active; then # do not apply no_turbo when power-profiles-daemon is running echo_message "Warning: CPU_BOOST_ON_BAT/BAT is not set because power-profiles-daemon is running." echo_debug "pm" "set_cpu_boost_all($1).intel_pstate.nop_ppd_active" return 0 fi # use intel_pstate sysfiles, invert value if write_sysf "$((val ^ 1))" $CPU_TURBO_PSTATE; then echo_debug "pm" "set_cpu_boost_all($1).intel_pstate: $val" else echo_debug "pm" "set_cpu_boost_all($1).intel_pstate.cpu_not_supported" fi elif [ -f $CPU_BOOST_ALL_CTRL ]; then # use acpi_cpufreq sysfiles # simple test for attribute "w" doesn't work, so actually write if write_sysf "$val" $CPU_BOOST_ALL_CTRL; then echo_debug "pm" "set_cpu_boost_all($1).acpi_cpufreq: $val" else echo_debug "pm" "set_cpu_boost_all($1).acpi_cpufreq.cpu_not_supported" fi else echo_debug "pm" "set_cpu_boost_all($1).not_available" fi return 0 } set_cpu_dyn_boost () { # set Intel/AMD CPU dynamic boost feature # - intel_state in HWP active mode # - amd_pstate in active mode, same requirements as set_cpu_perf_policy() # $1: 0=ac mode, 1=battery mode local val if [ "$1" = "1" ]; then val=${CPU_HWP_DYN_BOOST_ON_BAT:-} else val=${CPU_HWP_DYN_BOOST_ON_AC:-} fi if [ -z "$val" ]; then echo_debug "pm" "set_cpu_dyn_boost($1).not_configured" elif check_intel_pstate; then if [ $INTEL_DYN_BOOST ]; then write_sysf "$val" $INTEL_DYN_BOOST echo_debug "pm" "set_cpu_dyn_boost($1).intel_pstate: $val; rc=$?" else echo_debug "pm" "set_cpu_dyn_boost($1).intel_pstate.not_supported" fi elif check_amd_pstate; then if [ $AMD_DYN_BOOST ]; then write_sysf "$val" $AMD_DYN_BOOST echo_debug "pm" "set_cpu_dyn_boost($1).amd_pstate: $val; rc=$?" else echo_debug "pm" "set_cpu_dyn_boost($1).amd_pstate.not_supported" fi else echo_debug "pm" "set_cpu_dyn_boost($1).no_driver" fi return 0 } # --- Misc set_nmi_watchdog () { # enable/disable nmi watchdog local nmiwd=${NMI_WATCHDOG:-} if [ -z "$nmiwd" ]; then # do nothing if unconfigured echo_debug "pm" "set_nmi_watchdog.not_configured" return 0 fi if [ -f /proc/sys/kernel/nmi_watchdog ]; then if write_sysf "$nmiwd" /proc/sys/kernel/nmi_watchdog; then echo_debug "pm" "set_nmi_watchdog: $nmiwd; rc=$?" else echo_debug "pm" "set_nmi_watchdog.disabled_by_kernel: $nmiwd" fi else echo_debug "pm" "set_nmi_watchdog.not_available" fi return 0 } # --- Platform set_platform_profile () { # set platform profile # $1: 0=ac mode, 1=battery mode local pwr if [ "$1" = "1" ]; then pwr=${PLATFORM_PROFILE_ON_BAT:-} else pwr=${PLATFORM_PROFILE_ON_AC:-} fi if [ -z "$pwr" ]; then # do nothing if unconfigured echo_debug "pm" "set_platform_profile($1).not_configured" return 0 fi if [ -f $FWACPID/platform_profile ]; then if check_ppd_active; then # do not apply platform profile when power-profiles-daemon is running echo_message "Warning: PLATFORM_PROFILE_ON_AC/BAT is not set because power-profiles-daemon is running." echo_debug "pm" "set_platform_profile($1).nop_ppd_active" return 0 fi if write_sysf "$pwr" $FWACPID/platform_profile; then echo_debug "pm" "set_platform_profile($1): $pwr" else echo_debug "pm" "set_platform_profile($1).write_error" fi else echo_debug "pm" "set_platform_profile($1).not_available" fi return 0 } ukui-power-manager/3rd/tlp/func.d/20-tlp-func-usb0000664000175000017500000002476715167661430020375 0ustar fengfeng#!/bin/sh # tlp-func-usb - USB Functions # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base # ---------------------------------------------------------------------------- # Constants readonly USBD=/sys/bus/usb/devices readonly USB_TIMEOUT_MS=2000 readonly USB_WWAN_VENDORS="0bdb 05c6 1199 2cb7" readonly USB_DONE=usb_done # ---------------------------------------------------------------------------- # Functions # --- USB Autosuspend usb_suspend_device () { # enable/disable usb autosuspend for a single device # except input, scanners and denylisted # $1: device syspath # $2: batch/udev # $3: auto=enable/on=disable local usbdev=$1 if [ -f "$usbdev/power/autosuspend_delay_ms" ]; then # device is autosuspendable local vendor usbid busdev dclass vendor="$(read_sysf "$usbdev/idVendor")" usbid="$vendor:$(read_sysf "$usbdev/idProduct")" busdev="Bus $(read_sysf "$usbdev/busnum") Dev $(read_sysf "$usbdev/devnum")" dclass="$(read_sysf "$usbdev/bDeviceClass")" local control="${3:-auto}" local caller="$2" local exc="" local chg=0 rc1=0 rc2=0 local drvlist="" # trace only: get drivers for all subdevices if [ "$X_USB_DRIVER_TRACE" = "1" ]; then local dl drvlist=$(for dl in "$usbdev"/*:*/driver; do readlink "$dl" | \ sed -r 's/.+\///'; done | sort -u | tr '\n' ' ') drvlist="(${drvlist% })" fi if wordinlist "$usbid" "$USB_ALLOWLIST"; then # device is in allowlist -- allowlist always wins control="auto" exc="_dev_allow" elif wordinlist "$usbid" "$USB_DENYLIST"; then # device is in denylist control="on" exc="_dev_deny" else local subdev # udev: wait for subdevices to populate [ "$caller" = "udev" ] && sleep 0.5 # check for hid subdevices for subdev in "$usbdev"/*:*; do if [ "$(read_sysf "$subdev/bInterfaceClass")" = "03" ]; then control="on" exc="_hid_deny" break fi done if [ -z "$exc" ]; then # check for bluetooth devices if [ "$USB_EXCLUDE_BTUSB" = "1" ] \ && [ "$dclass" = "e0" ] \ && [ "$(read_sysf "$usbdev/bDeviceSubClass")" = "01" ] \ && [ "$(read_sysf "$usbdev/bDeviceProtocol")" = "01" ]; then control="on" exc="_btusb_deny" fi fi # bluetooth if [ -z "$exc" ]; then # check for audio devices if [ "$USB_EXCLUDE_AUDIO" = "1" ]; then for subdev in "$usbdev"/*:*; do if [ "$(read_sysf "$subdev/bInterfaceClass")" = "01" ]; then control="on" exc="_audio_deny" break fi done fi fi # audio if [ -z "$exc" ]; then # check for scanners: # libsane_matched envvar is set by libsane's udev rules # shellcheck disable=SC2154 if [ "$libsane_matched" = "yes" ] || [ "$2" = "batch" ] \ && $UDEVADM info -q property "$usbdev" 2>/dev/null | grep -q 'libsane_matched=yes'; then # do not touch this device control="deny" exc="_libsane" fi fi if [ -z "$exc" ]; then # check for phone devices if [ "$USB_EXCLUDE_PHONE" = "1" ]; then if [ "$vendor" = "0fca" ]; then # RIM if [ "$dclass" = "ef" ]; then # RIM / BlackBerry control="on" exc="_phone_deny" elif [ "$dclass" = "00" ]; then for subdev in "$usbdev"/*:*; do if [ -d "$subdev" ]; then if [ "$(read_sysf "$subdev/interface")" = "BlackBerry" ]; then # Blackberry control="on" exc="_phone_deny" break fi fi done fi elif [ "$vendor" = "045e" ] && [ "$dclass" = "ef" ]; then # Windows Phone control="on" exc="_phone_deny" elif [ "$vendor" = "05ac" ] && [ "$(read_sysf "$usbdev/product")" = "iPhone" ]; then # iPhone control="on" exc="_phone_deny" elif [ "$dclass" = "00" ]; then # class defined at interface level, iterate subdevices for subdev in "$usbdev"/*:*; do if [ -d "$subdev" ]; then if [ "$(read_sysf "$subdev/interface")" = "MTP" ]; then # MTP: mostly Android control="on" exc="_phone_deny" break elif [ "$(read_sysf "$subdev/bInterfaceClass")" = "ff" ] \ && [ "$(read_sysf "$subdev/bInterfaceSubClass")" = "42" ] \ && [ "$(read_sysf "$subdev/bInterfaceProtocol")" = "01" ]; then # ADB: Android control="on" exc="_phone_deny" break elif [ "$(read_sysf "$subdev/bInterfaceClass")" = "06" ] \ && [ "$(read_sysf "$subdev/bInterfaceSubClass")" = "01" ] \ && [ "$(read_sysf "$subdev/bInterfaceProtocol")" = "01" ]; then # PTP: iPhone, Lumia et al. # caveat: may also be a camera control="on" exc="_phone_deny" break fi fi done fi # dclass 00 fi # exclude phone fi # phone if [ -z "$exc" ]; then # check for printers if [ "$USB_EXCLUDE_PRINTER" = "1" ]; then if [ "$dclass" = "00" ]; then # check for printer subdevices for subdev in "$usbdev"/*:*; do if [ "$(read_sysf "$subdev/bInterfaceClass")" = "07" ]; then control="on" exc="_printer_deny" break fi done fi fi fi # printer if [ -z "$exc" ]; then # check for wwan devices if [ "$USB_EXCLUDE_WWAN" = "1" ]; then if [ "$dclass" != "00" ]; then # check for cdc subdevices for subdev in "$usbdev"/*:*; do if [ "$(read_sysf "$subdev/bInterfaceClass")" = "0a" ]; then control="on" exc="_wwan_deny" break fi done fi if [ -z "$exc" ]; then # check for vendors if wordinlist "$vendor" "$USB_WWAN_VENDORS"; then control="on" exc="_wwan_deny" fi fi fi # exclude wwan fi # wwan fi # !device denylist if [ "$(read_sysf "$usbdev/power/control")" != "$control" ]; then # set control, write actual changes only case $control in auto|on) write_sysf "$control" "$usbdev/power/control"; rc1=$? chg=1 ;; deny) # do not touch denylisted device ;; esac fi if [ "$X_TLP_USB_SET_AUTOSUSPEND_DELAY" = "1" ]; then # set autosuspend delay write_sysf $USB_TIMEOUT_MS "$usbdev/power/autosuspend_delay_ms"; rc2=$? echo_debug "usb" "usb_suspend_device.$caller.$control$exc: $busdev ID $usbid $usbdev [$drvlist]; control: rc=$rc1; delay: rc=$rc2" elif [ $chg -eq 1 ]; then # default: change control but not autosuspend_delay, i.e. keep kernel default setting echo_debug "usb" "usb_suspend_device.$caller.$control$exc: $busdev ID $usbid $usbdev [$drvlist]; control: rc=$rc1" else # we didn't change anything actually echo_debug "usb" "usb_suspend_device.$caller.$control$exc.no_change: $busdev ID $usbid $usbdev [$drvlist]" fi fi # autosuspendable return 0 } set_usb_suspend () { # enable/disable usb autosuspend for all devices # $1: 0=silent/1=report result # $2: auto=enable/on=disable local usbdev if [ "$USB_AUTOSUSPEND" = "1" ]; then # autosuspend is configured --> iterate devices for usbdev in "$USBD"/*; do case "$usbdev" in *:*) ;; # colon in device name --> do nothing *) usb_suspend_device "$usbdev" "batch" "$2" ;; esac done [ "$1" = "1" ] && echo "USB autosuspend settings applied." echo_debug "usb" "set_usb_suspend.done" # set "startup completion" flag for tlp-usb-udev set_run_flag $USB_DONE else [ "$1" = "1" ] && echo "Error: USB autosuspend is disabled. Set USB_AUTOSUSPEND=1 in ${CONF_USR}." 1>&2 echo_debug "usb" "set_usb_suspend.not_configured" fi return 0 } ukui-power-manager/3rd/tlp/func.d/15-tlp-func-disk0000664000175000017500000005321115167661430020524 0ustar fengfeng#!/bin/sh # tlp-func-disk - Storage Device and Filesystem Functions # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base # ---------------------------------------------------------------------------- # Constants readonly AHCID=$PCID'/*/ata*' readonly ALPMD=$AHCID'/host*/scsi_host/host*' readonly DISK_NOP_WORDS="_ keep" # ---------------------------------------------------------------------------- # Functions # --- Device Helpers get_disk_dev () { # translate disk id to device (sdX) # and determine disk type and capabilities # $1: id or device basename # $2: target disk device (optional) # rc: 0=disk exists (optional: amd matches target) # 1=disk non-existent (optional: or does not match target) # retval: $_disk_dev: device basename - below /dev or /sys/block; # $_disk_id: id basename - below /dev/disk/by-id; # $_disk_type: nvme/ata/sata/usb/ieee1394; # $_disk_apm: 0=no apm/1=apm capable; # $_disk_mq: scheduler: 0=single queue/1=multi queue; # $_disk_runpm: runtime pm: 0=allowed/1=denied by kernel/2=denied by tlp/3=incapable local dev id idpath local target="$2" _disk_dev="" if [ -h "/dev/disk/by-id/$1" ]; then # $1 is disk id _disk_id=$1 _disk_dev=$(printf '%s' "$_disk_id" | sed -r 's/-part[1-9][0-9]*$//') _disk_dev=$(readlink "/dev/disk/by-id/$_disk_dev") _disk_dev=${_disk_dev##*/} else # $1 is disk dev _disk_dev=$1 _disk_id="" if [ -b "/dev/$_disk_dev" ]; then # disk exists, lookup id for idpath in /dev/disk/by-id/*; do id="${idpath##*/}" # filter partitions [ -n "${id%%*-part[1-9]*}" ] || continue case "$id" in ata-*|usb-*) dev=$(readlink "$idpath") dev=${dev##*/} if [ "$dev" = "$_disk_dev" ]; then _disk_id="$id" break fi ;; nvme-*) # filter 'nvme-eui.*' if [ -n "${id##nvme-eui.*}" ]; then dev=$(readlink "$idpath") dev=${dev##*/} if [ "$dev" = "$_disk_dev" ]; then _disk_id="$id" break fi fi ;; esac done fi fi if [ -b "/dev/$_disk_dev" ]; then # retrieve device attributes local bus dpath path udevadm_data local DEVPATH= local ID_PATH= local ID_BUS= local ID_ATA_FEATURE_SET_PM_ENABLED= if udevadm_data="$( $UDEVADM info -q property "/dev/$_disk_dev" 2>/dev/null | \ grep -E '^(DEVPATH|ID_BUS|ID_PATH|ID_ATA_FEATURE_SET_PM_ENABLED)=' )"; then eval "${udevadm_data}" fi # determine device type (bus) path="$ID_PATH" bus="$ID_BUS" case "$path" in pci-*-nvme-*) _disk_type="nvme" ;; pci-*-ata-*) _disk_type="ata" ;; pci-*-usb-*) _disk_type="usb" ;; pci-*-ieee1394-*) _disk_type="ieee1394" ;; *) case "$bus" in nvme) _disk_type="nvme" ;; ata) _disk_type="ata" ;; usb) _disk_type="usb" ;; ieee1394) _disk_type="ieee1394" ;; *) dpath="${DEVPATH##*/}" case $dpath in nvme*) _disk_type="nvme" ;; *) _disk_type="unknown" ;; esac ;; esac esac # distinguish sata from ata(ide) disks if [ "$_disk_type" = "ata" ]; then if glob_files "/link_power_management_policy" "/sys${DEVPATH%/target*}/scsi_host/host*" > /dev/null 2>&1; then _disk_type=sata fi fi # determine APM capability _disk_apm=0 if [ "$ID_ATA_FEATURE_SET_PM_ENABLED" = "1" ]; then _disk_apm=1 fi # determine if single- or multi-queue scheduler if [ -d "/sys/block/$_disk_dev/mq" ]; then _disk_mq="1" else _disk_mq="0" fi # determine if runtime pm is possible and allowed if [ -f "/sys/block/$_disk_dev/device/power/control" ]; then # disk has a runtime pm control sysfile case "$_disk_type" in nvme) # nvme disks do not have a readable autosuspend_delay_ms, # nevertheless runtime pm changes are safe _disk_runpm="0" ;; sata|ata|usb) if ! readable_sysf "/sys/block/$_disk_dev/device/power/autosuspend_delay_ms"; then # autosuspend_delay_ms is missing or not readable # --> kernel itself denies runtime pm for the disk _disk_runpm="1" else # kernel allows runtime pm for the disk # --> tlp decides if it is safe if [ "$_disk_mq" = "0" ] || kernel_version_ge 4.19; then # singlequeue scheduler is considered safe for all kernels, # multiqueue and kernel >= 4.19 too _disk_runpm="0" else # multiqueue scheduler and kernel < 4.19 is considered unsafe, # because system freezes and data loss may occur when enabling # runtime pm for a sata or ata disk. # only with kernel 4.19 a lock was introduced which prevents that mq # is forced via command line options: # https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v4.19&id=b233f127042dba991229e3882c6217c80492f6ef # distribution kernels < 4.19 may be patched too, but better safe than sorry. _disk_runpm="2" fi fi ;; *) # tlp shall not (yet) touch runtime pm for other disk types _disk_runpm="2" ;; esac else # disk is not runtime pm capable _disk_runpm="3" fi if [ -n "$target" ]; then # in target mode trace output only in case of match if [ "$target" = "$_disk_dev" ]; then echo_debug "disk" "get_disk_dev($1).target: dev=$_disk_dev; id=$_disk_id; type=$_disk_type; path=$path; bus=$bus; dpath=$dpath; apm=$_disk_apm; mq=$_disk_mq; runpm=$_disk_runpm" return 0 else # no match return 1 fi else echo_debug "disk" "get_disk_dev($1): dev=$_disk_dev; id=$_disk_id; type=$_disk_type; path=$path; bus=$bus; dpath=$dpath; apm=$_disk_apm; mq=$_disk_mq; runpm=$_disk_runpm" return 0 fi else _disk_type="none" echo_debug "disk" "get_disk_dev($1).missing" return 1 fi } show_disk_ids () { # show disk id's local dev local shown="" { # iterate SATA and NVMe disks for dev in $(glob_files '/*' /dev/disk/by-id/ | sed -rn 's/.*\/((ata|ieee1394|nvme|usb))/\1/p' | grep -E -v '(^nvme-eui|-part[1-9]+)'); do if [ -n "$dev" ] && get_disk_dev "$dev" && ! wordinlist "$_disk_dev" "$shown" ; then printf '%s: %s\n' "$_disk_dev" "$_disk_id" shown="$shown $_disk_dev" fi done } | sort return 0 } # --- Disk APM Features set_disk_apm_level () { # set disk apm level # $1: 0=ac mode, 1=battery mode # $2: target disk device (optional) local pwrmode="$1" local target="$2" local dev log_message # quit when disabled if [ -z "$DISK_DEVICES" ]; then echo_debug "disk" "set_disk_apm_level($pwrmode).disabled" return 0 fi # set @argv := apmlist (blanks removed - relying on a sane $IFS) if [ "$pwrmode" = "1" ]; then # shellcheck disable=SC2086 set -- $DISK_APM_LEVEL_ON_BAT else # shellcheck disable=SC2086 set -- $DISK_APM_LEVEL_ON_AC fi # quit if empty apmlist if [ $# -eq 0 ]; then echo_debug "disk" "set_disk_apm_level($pwrmode).not_configured" return 0 fi if [ -z "$target" ]; then echo_debug "disk" "*** set_disk_apm_level($pwrmode).all" else echo_debug "disk" "*** set_disk_apm_level($pwrmode).target: $target" fi # pairwise iteration DISK_DEVICES[1,n], apmlist[1,m]; m > 0 # for j in [1,n]: disk_dev[j], apmlist[min(j,m)] # operation modes: # 1. work on all disks in $DISK_DEVICES # 2. work on $target only -- when called by udev event for dev in $DISK_DEVICES; do : "${1:?BUG: broken DISK_APM_LEVEL list handling}" if get_disk_dev "$dev" "$target"; then log_message="set_disk_apm_level($pwrmode): $_disk_dev [$_disk_id] $1" if wordinlist "$_disk_type" "$DISK_APM_CLASS_DENYLIST"; then echo_debug "disk" "${log_message}; class denylist" elif [ "$_disk_apm" = "0" ]; then echo_debug "disk" "${log_message}; not supported" elif wordinlist "$1" "$DISK_NOP_WORDS"; then echo_debug "disk" "${log_message}; keep as is" else $HDPARM -B "$1" "/dev/$_disk_dev" > /dev/null 2>&1 echo_debug "disk" "${log_message}; rc=$?" fi fi # quit the loop after reaching the target [ -n "$target" ] && [ "$target" = "$_disk_dev" ] && break # last entry in apmlist applies to all remaining disks [ $# -lt 2 ] || shift done return 0 } set_disk_spindown_timeout () { # set disk spindown timeout # $1: 0=ac mode, 1=battery mode # $2: target disk device (optional) local pwrmode="$1" local target="$2" local dev log_message # quit when disabled if [ -z "$DISK_DEVICES" ]; then echo_debug "disk" "set_disk_spindown_timeout($pwrmode).disabled" return 0 fi # set @argv := timeoutlist if [ "$pwrmode" = "1" ]; then # shellcheck disable=SC2086 set -- $DISK_SPINDOWN_TIMEOUT_ON_BAT else # shellcheck disable=SC2086 set -- $DISK_SPINDOWN_TIMEOUT_ON_AC fi # quit if empty timeoutlist if [ $# -eq 0 ]; then echo_debug "disk" "set_disk_spindown_timeout($pwrmode).not_configured" return 0 fi if [ -z "$target" ]; then echo_debug "disk" "*** set_disk_spindown_timeout($pwrmode).all" else echo_debug "disk" "*** set_disk_spindown_timeout($pwrmode).target: $target" fi # pairwise iteration DISK_DEVICES[1,n], timeoutlist[1,m]; m > 0 # for j in [1,n]: disk_dev[j], timeoutlist[min(j,m)] # operation modes: # 1. work on all disks in $DISK_DEVICES # 2. work on $target only -- when called by udev event for dev in $DISK_DEVICES; do : "${1:?BUG: broken DISK_SPINDOWN_TIMEOUT list handling}" if get_disk_dev "$dev" "$target"; then log_message="set_disk_spindown_timeout($pwrmode): $_disk_dev [$_disk_id] $1" if wordinlist "$1" "$DISK_NOP_WORDS"; then echo_debug "disk" "${log_message}; keep as is" else $HDPARM -S "$1" "/dev/$_disk_dev" > /dev/null 2>&1 echo_debug "disk" "${log_message}; rc=$?" fi fi # quit the loop after reaching the target [ -n "$target" ] && [ "$target" = "$_disk_dev" ] && break # last entry in timeoutlist applies to all remaining disks [ $# -lt 2 ] || shift done return 0 } spindown_disk () { # stop spindle motor -- $1: dev $HDPARM -y "/dev/$1" > /dev/null 2>&1 return 0 } set_disk_iosched () { # set disk io scheduler # $1: target disk device (optional) local target="$1" local dev log_message # quit when disabled if [ -z "$DISK_DEVICES" ]; then echo_debug "disk" "set_disk_iosched.disabled" return 0 fi # set @argv := schedlist # shellcheck disable=SC2086 set -- $DISK_IOSCHED # quit if empty schedlist if [ $# -eq 0 ]; then echo_debug "disk" "set_disk_iosched.not_configured" return 0 fi if [ -z "$target" ]; then echo_debug "disk" "*** set_disk_iosched($pwrmode).all" else echo_debug "disk" "*** set_disk_iosched($pwrmode).target: $target" fi # pairwise iteration DISK_DEVICES[1,n], schedlist[1,m]; m > 0 # for j in [1,min(n,m)] : disk_dev[j], schedlistj] # for j in [min(n,m)+1,n] : disk_dev[j], %keep # operation modes: # 1. work on all disks in $DISK_DEVICES # 2. work on $target only -- when called by udev event for dev in $DISK_DEVICES; do local sched schedctrl if get_disk_dev "$dev" "$target"; then # get sched from argv, use "keep" when list is too short sched=${1:-keep} schedctrl="/sys/block/$_disk_dev/queue/scheduler" log_message="set_disk_iosched: $_disk_dev [$_disk_id] $sched" if [ ! -f "$schedctrl" ]; then echo_debug "disk" "${log_message}; not supported" elif wordinlist "$sched" "$DISK_NOP_WORDS"; then echo_debug "disk" "${log_message}; keep as is" else write_sysf "$sched" "$schedctrl" echo_debug "disk" "${log_message}; rc=$?" fi fi # quit the loop after reaching the target [ -n "$target" ] && [ "$target" = "$_disk_dev" ] && break # using "keep" when argv is empty [ $# -eq 0 ] || shift done return 0 } # --- Power Saving set_sata_link_power () { # set ahci link power management # $1: 0=ac mode, 1=battery mode local pm="$1" local host host_bl hostid linkpol pwr rc local pwrlist="" local ctrl_avail="0" if [ "$pm" = "1" ]; then pwrlist=${SATA_LINKPWR_ON_BAT:-} else pwrlist=${SATA_LINKPWR_ON_AC:-} fi if [ -z "$pwrlist" ]; then # do nothing if unconfigured echo_debug "disk" "set_sata_link_power($pm).not_configured" return 0 fi # ALPM denylist host_bl=${SATA_LINKPWR_DENYLIST:-} # copy configured values to args # shellcheck disable=SC2086 set -- $pwrlist # iterate SATA hosts for host in $ALPMD ; do linkpol="$host/link_power_management_policy" if [ -f "$linkpol" ]; then hostid=${host##*/} if wordinlist "$hostid" "$host_bl"; then # host denylisted --> skip echo_debug "disk" "set_sata_link_power($pm).deny: $host" ctrl_avail="1" else # host not denylisted --> iterate all configured values for pwr in "$@"; do write_sysf "$pwr" "$linkpol"; rc=$? echo_debug "disk" "set_sata_link_power($pm).$pwr: $host; rc=$rc" if [ $rc -eq 0 ]; then # write successful --> goto next host ctrl_avail="1" break else # write failed --> don't use this value for remaining hosts # and try next value shift fi done fi fi done [ "$ctrl_avail" = "0" ] && echo_debug "disk" "set_sata_link_power($pm).not_available" return 0 } set_ahci_disk_runtime_pm () { # set runtime power management for ahci disks # $1: 0=ac mode, 1=battery mode, 2=suspend mode # $2: target disk device (optional) local target="$2" local control dev timeout rc case "$1" in 0) control=${AHCI_RUNTIME_PM_ON_AC:-} ;; 1) control=${AHCI_RUNTIME_PM_ON_BAT:-} ;; 2) # reset on suspend only when configured if [ -n "${AHCI_RUNTIME_PM_ON_AC:-}${AHCI_RUNTIME_PM_ON_BAT:-}" ]; then control="on" fi ;; esac # calc timeout in millisecs timeout="$AHCI_RUNTIME_PM_TIMEOUT" [ -z "$timeout" ] || timeout=$((timeout * 1000)) # check values case "$control" in on|auto) ;; *) control="" ;; # invalid input --> unconfigured esac if [ -z "$control" ]; then # do nothing if unconfigured echo_debug "disk" "set_ahci_disk_runtime_pm($1).not_configured" return 0 fi # when timeout is unconfigured we're done here if [ -z "$timeout" ]; then echo_debug "disk" "set_ahci_disk_runtime_pm($1).timeout_not_configured" return 0 fi if [ -z "$target" ]; then echo_debug "disk" "*** set_ahci_disk_runtime_pm($pwrmode).all" else echo_debug "disk" "*** set_ahci_disk_runtime_pm($pwrmode).target: $target" fi # iterate DISK_DEVICES for dev in $DISK_DEVICES; do if get_disk_dev "$dev" "$target"; then case "$_disk_runpm" in 0) # runtime pm allowed for disk rc=0 # write timeout first to prevent lockups if ! write_sysf "$timeout" "/sys/block/$_disk_dev/device/power/autosuspend_delay_ms"; then # writing timeout failed rc=1 fi # proceed with activation if ! write_sysf "$control" "/sys/block/$_disk_dev/device/power/control"; then # activation failed rc=2 fi echo_debug "disk" "set_ahci_disk_runtime_pm($1).$control: disk=$_disk_dev timeout=$timeout; rc=$rc" ;; 1|2) # runtime pm denied for disk echo_debug "disk" "set_ahci_disk_runtime_pm($1).denied: disk=$_disk_dev; runpm=$_disk_runpm" ;; 3) # disk not runtime pm capable echo_debug "disk" "set_ahci_disk_runtime_pm($1).incapable: disk=$_disk_dev; runpm=$_disk_runpm" ;; esac fi # quit the loop after reaching the target [ -n "$target" ] && [ "$target" = "$_disk_dev" ] && break done return 0 } set_ahci_port_runtime_pm () { # set runtime power management for ahci ports # $1: 0=ac mode, 1=battery mode, 2=suspend mode local control device case "$1" in 0) control=${AHCI_RUNTIME_PM_ON_AC:-} ;; 1) control=${AHCI_RUNTIME_PM_ON_BAT:-} ;; 2) # reset on suspend only when configured if [ -n "${AHCI_RUNTIME_PM_ON_AC:-}${AHCI_RUNTIME_PM_ON_BAT:-}" ]; then control="on" fi ;; esac # check values case "$control" in on|auto) ;; *) control="" ;; # invalid input --> unconfigured esac if [ -z "$control" ]; then # do nothing if unconfigured echo_debug "disk" "set_ahci_port_runtime_pm($1).not_configured" return 0 fi # iterate ahci ports for device in $AHCID; do if write_sysf "$control" "${device}/power/control"; then echo_debug "disk" "set_ahci_port_runtime_pm($1).$control: port=$device; rc=0" else echo_debug "disk" "set_ahci_port_runtime_pm($1).no-port" fi done return 0 } # --- Filesystem Parameters set_laptopmode () { # set kernel laptop mode # $1: 0=ac mode, 1=battery mode local isec if [ "$1" = "1" ]; then isec="$DISK_IDLE_SECS_ON_BAT" else isec="$DISK_IDLE_SECS_ON_AC" fi # replace with empty string if non-numeric chars are contained isec=$(printf '%s' "$isec" | grep -E '^[0-9]+$') if [ -z "$isec" ]; then # do nothing if unconfigured or non numeric value echo_debug "disk" "set_laptopmode($1).not_configured" return 0 fi write_sysf "$isec" /proc/sys/vm/laptop_mode echo_debug "disk" "set_laptopmode($1): $isec; rc=$?" return 0 } set_dirty_parms () { # set filesystem buffer params # $1: 0=ac mode, 1=battery mode local age cage df ec if [ "$1" = "1" ]; then age=${MAX_LOST_WORK_SECS_ON_BAT:-0} else age=${MAX_LOST_WORK_SECS_ON_AC:-0} fi # calc age in centisecs, non numeric values result in "0" cage=$((age * 100)) if [ "$cage" = "0" ]; then # do nothing if unconfigured or invalid age echo_debug "disk" "set_dirty_parms($1).not_configured" return 0 fi ec=0 for df in /proc/sys/vm/dirty_writeback_centisecs \ /proc/sys/vm/dirty_expire_centisecs \ /proc/sys/fs/xfs/age_buffer_centisecs \ /proc/sys/fs/xfs/xfssyncd_centisecs; do if [ -f "$df" ] && ! write_sysf "$cage" $df; then echo_debug "disk" "set_dirty_parms($1).write_error: $df $cage; rc=$?" ec=$((ec+1)) fi done # shellcheck disable=SC2043 for df in /proc/sys/fs/xfs/xfsbufd_centisecs; do if [ -f "$df" ] && ! write_sysf "3000" $df; then echo_debug "disk" "set_dirty_parms($1).write_error: $df 3000; rc=$?" ec=$((ec+1)) fi done echo_debug "disk" "set_dirty_parms($1): $cage; ec=$ec" return 0 } ukui-power-manager/3rd/tlp/func.d/05-tlp-func-pm0000664000175000017500000002030015167661430020176 0ustar fengfeng#!/bin/sh # tlp-func-pm - Device Power Management Functions # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base # ---------------------------------------------------------------------------- # Constants readonly ETHTOOL=ethtool readonly PCID=/sys/bus/pci/devices readonly PCIDRV=/sys/bus/pci/drivers readonly SLEEPMODE=/sys/power/mem_sleep # ---------------------------------------------------------------------------- # Functions # --- PCI(e) Devices set_runtime_pm () { # set runtime power management # $1: 0=ac mode, 1=battery mode local address class control device driver drv_bl type local pci_bl_adr="" local pci_bl_drv="" local pci_enable_adr pci_disable_adr if [ "$1" = "1" ]; then control=${RUNTIME_PM_ON_BAT:-} else control=${RUNTIME_PM_ON_AC:-} fi # permanent addresses pci_enable_adr=${RUNTIME_PM_ENABLE:-} pci_disable_adr=${RUNTIME_PM_DISABLE:-} if [ -z "$control" ] && [ -z "$pci_enable_adr" ] && [ -z "$pci_disable_adr" ] ; then # quit if completely unconfigured echo_debug "pm" "set_runtime_pm($1).not_configured" return 0 fi case "$control" in auto|on|"") # valid control value or no operation ("") ;; *) # invalid control value echo_debug "pm" "set_runtime_pm($1).invalid: $control" return 0 ;; esac if [ -n "$control" ]; then # RUNTIME_PM_ON_AC/BAT is configured --> prepare denylists # driver specific denylist: # - undefined = use intrinsic default from /usr/share/tlp/defaults.conf # - empty = disable feature drv_bl="$RUNTIME_PM_DRIVER_DENYLIST" # pci address denylisting pci_bl_adr=${RUNTIME_PM_DENYLIST:-} # pci driver denylisting: corresponding pci addresses pci_bl_drv="" # cumulate pci addresses for devices with denylisted drivers for driver in $drv_bl; do # iterate list if [ -n "$driver" ] && [ -d "$PCIDRV/$driver" ]; then # driver is active --> iterate over assigned devices for device in "$PCIDRV/$driver/0000:"*; do # get short device address address=${device##/*/0000:} # add to list when not already contained if ! wordinlist "$address" "$pci_bl_drv"; then pci_bl_drv="$pci_bl_drv $address" fi done # for device fi # if driver done # for driver fi # iterate pci(e) devices for type in $PCID; do for device in "$type"/*; do if [ -f "$device/power/control" ]; then # get short device address, class address=${device##/*/0000:} class=$(read_sysf "$device/class") if wordinlist "$address" "$pci_enable_adr"; then # device should be permanently 'auto' (enabled) write_sysf "auto" "$device/power/control" echo_debug "pm" "set_runtime_pm($1).perm_auto: $device [$class]; rc=$?" elif wordinlist "$address" "$pci_disable_adr"; then # device should be permanently 'on' (disabled) write_sysf "on" "$device/power/control" echo_debug "pm" "set_runtime_pm($1).perm_on: $device [$class]; rc=$?" elif wordinlist "$address" "$pci_bl_adr"; then # device is in address denylist echo_debug "pm" "set_runtime_pm($1).deny_address: $device [$class]" elif wordinlist "$address" "$pci_bl_drv"; then # device is in driver denylist echo_debug "pm" "set_runtime_pm($1).deny_driver: $device [$class]" else case $control in auto|on) write_sysf "$control" "$device/power/control" echo_debug "pm" "set_runtime_pm($1).$control: $device [$class]; rc=$?" ;; "") # no operation i.e. apply RUNTIME_PM_ENABLE/DISABLE only echo_debug "pm" "set_runtime_pm($1).nop: $device [$class]" ;; esac fi # if denylist fi # if power/control done # for device done # for type return 0 } set_pcie_aspm () { # set pcie active state power management # $1: 0=ac mode, 1=battery mode local pwr="" case "$1" in 0) pwr="${PCIE_ASPM_ON_AC:-}" ;; 1) pwr="${PCIE_ASPM_ON_BAT:-}" ;; 2) # reset on suspend only when configured if [ -n "${PCIE_ASPM_ON_AC:-}${PCIE_ASPM_ON_BAT:-}" ]; then pwr="default" fi ;; esac if [ -z "$pwr" ]; then # do nothing if unconfigured echo_debug "pm" "set_pcie_aspm($1).not_configured" return 0 fi if [ -f /sys/module/pcie_aspm/parameters/policy ]; then if write_sysf "$pwr" /sys/module/pcie_aspm/parameters/policy; then echo_debug "pm" "set_pcie_aspm($1): $pwr" else echo_debug "pm" "set_pcie_aspm($1).disabled_by_kernel" fi else echo_debug "pm" "set_pcie_aspm($1).not_available" fi return 0 } # -- Audio Devices set_sound_power_mode () { # set sound chip power modes # $1: 0=ac mode, 1=battery mode local pwr cpwr # new config param if [ "$1" = "1" ]; then pwr=${SOUND_POWER_SAVE_ON_BAT:-} else pwr=${SOUND_POWER_SAVE_ON_AC:-} fi # when unconfigured consider legacy config param [ -z "$pwr" ] && pwr=${SOUND_POWER_SAVE:-} if [ -z "$pwr" ]; then # do nothing if unconfigured echo_debug "pm" "set_sound_power_mode($1).not_configured" return 0 fi cpwr="$SOUND_POWER_SAVE_CONTROLLER" if [ -d /sys/module/snd_hda_intel ]; then write_sysf "$pwr" /sys/module/snd_hda_intel/parameters/power_save echo_debug "pm" "set_sound_power_mode($1).hda: $pwr; rc=$?" if [ "$pwr" = "0" ]; then write_sysf "N" /sys/module/snd_hda_intel/parameters/power_save_controller echo_debug "pm" "set_sound_power_mode($1).hda_controller: N controller=$cpwr; rc=$?" else write_sysf "$cpwr" /sys/module/snd_hda_intel/parameters/power_save_controller echo_debug "pm" "set_sound_power_mode($1).hda_controller: $cpwr; rc=$?" fi fi if [ -d /sys/module/snd_ac97_codec ]; then write_sysf "$pwr" /sys/module/snd_ac97_codec/parameters/power_save echo_debug "pm" "set_sound_power_mode($1).ac97: $pwr; rc=$?" fi return 0 } # --- LAN Devices get_ethifaces () { # get all eth devices -- retval: $_ethifaces local ei eic _ethifaces="" for eic in "$NETD"/*/device/class; do if [ "$(read_sysf "$eic")" = "0x020000" ] \ && [ ! -d "${eic%/class}/ieee80211" ]; then ei=${eic%/device/class}; ei=${ei##*/} _ethifaces="$_ethifaces $ei" fi done _ethifaces="${_ethifaces# }" return 0 } disable_wake_on_lan () { # disable WOL local ei if [ "$WOL_DISABLE" = "Y" ]; then get_ethifaces for ei in $_ethifaces; do $ETHTOOL -s "$ei" wol d > /dev/null 2>&1 echo_debug "pm" "disable_wake_on_lan: $ei; rc=$?" done else echo_debug "pm" "disable_wake_on_lan.not_configured" fi return 0 } # --- Set suspend method set_mem_sleep () { # $1: 0=ac mode, 1=battery mode local susp if [ "$1" = "1" ]; then susp=${MEM_SLEEP_ON_BAT:-} else susp=${MEM_SLEEP_ON_AC:-} fi if [ -z "$susp" ]; then # do nothing if unconfigured echo_debug "pm" "set_mem_sleep($1).not_configured" return 0 fi if [ -f $SLEEPMODE ]; then if write_sysf "$susp" $SLEEPMODE; then echo_debug "pm" "set_mem_sleep($1): $susp" else echo_debug "pm" "set_mem_sleep($1).rejected_by_kernel" fi else echo_debug "pm" "set_mem_sleep($1).not_available" fi return 0 } ukui-power-manager/3rd/tlp/func.d/35-tlp-func-batt0000664000175000017500000001453015167661430020527 0ustar fengfeng#!/bin/sh # tlp-func-batt - Battery Feature Functions # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 34-tlp-func-platform # ---------------------------------------------------------------------------- # Constants # shellcheck disable=SC2034 readonly ACPIBATDIR=/sys/class/power_supply # ---------------------------------------------------------------------------- # Functions init_batteries_thresholds () { # apply thresholds from configuration to all batteries # optional depending on active plugin when specified in $1 # - called from bg tasks tlp init [re]start/auto and tlp start # $1: plugin list (space separated) # rc: 0=ok/ # 1=battery not present/ # 2=threshold(s) out of range or non-numeric/ # 3=minimum start stop diff violated/ # 4=read error/ # 5=write error/ # 6=threshold write discarded by kernel or firmware/ # 255=no thresh api local rc # select battery feature driver select_batdrv # shellcheck disable=SC2154 if [ "$_bm_thresh" = "none" ]; then # thresholds not available --> quit echo_debug "bat" "set_charge_thresholds.no_method" return 255 fi # apply thresholds # shellcheck disable=SC2154 if [ -z "$1" ]; then batdrv_apply_configured_thresholds; rc=$? elif wordinlist "$_batdrv_plugin" "$1"; then batdrv_apply_configured_thresholds; rc=$? fi return $rc } setcharge_battery () { # apply charge thresholds for a single battery # - called from cmdline tlp setcharge/fullcharge/recalibrate # $1: start charge threshold, # $2: stop charge threshold # $3: battery # $4: error msg addenum # rc: 0=ok/ # 1=battery not present/ # 2=threshold(s) out of range or non-numeric/ # 3=minimum start stop diff violated/ # 4=read error/ # 5=write error/ # 6=threshold write discarded by kernel or firmware/ # 255=no thresh api local bat rc start_thresh stop_thresh local use_cfg=0 # select battery feature driver select_batdrv # shellcheck disable=SC2154 if [ "$_bm_thresh" = "none" ]; then # thresholds not available --> quit printf "Error: battery charge thresholds%s not available.\n" "${4:-}" 1>&2 echo_debug "bat" "setcharge_battery.no_method" return 255 fi # check params case $# in 0) # no args bat=DEF # use default(1st) battery use_cfg=1 # use configured values ;; 1) # assume $1 is battery bat=$1 use_cfg=1 # use configured values ;; 2) # assume $1,$2 are thresholds start_thresh=$1 stop_thresh=$2 bat=DEF # use default(1st) battery ;; 3|4) # assume $1,$2 are thresholds, $3 is battery start_thresh=$1 stop_thresh=$2 bat=${3:-DEF} ;; esac # check bat presence and/or get default(1st) battery if batdrv_select_battery "$bat"; then # battery present -> get configured values if requested if [ $use_cfg -eq 1 ]; then # shellcheck disable=SC2154 eval start_thresh="\$START_CHARGE_THRESH_${_bt_cfg_bat}" # shellcheck disable=SC2154 eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" fi else # battery not present printf "Error: battery %s not present.\n" "$bat" 1>&2 echo_debug "bat" "setcharge_battery.not_present($bat)" return 1 fi # apply thresholds if [ $use_cfg -eq 1 ]; then # from configuration batdrv_write_thresholds "$start_thresh" "$stop_thresh" 2 1; rc=$? else # from command line batdrv_write_thresholds "$start_thresh" "$stop_thresh" 2; rc=$? fi return $rc } chargeonce_battery () { # charge battery to upper threshold once # $1: battery # rc: 0=ok/1=battery no present/255=no api local bat rc # select battery feature driver select_batdrv if [ "$_bm_thresh" = "none" ]; then # thresholds not available --> quit printf "Error: battery charge thresholds not available.\n" 1>&2 echo_debug "bat" "chargeonce_battery.no_method" return 255 fi # check params if [ $# -gt 0 ]; then # parameter(s) given, check $1 bat=${1:-DEF} bat=$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]") else # no parameters given, use default(1st) battery bat=DEF fi # check bat presence and/or get default(1st) battery if ! batdrv_select_battery "$bat"; then # battery not present printf "Error: battery %s not present.\n" "$bat" 1>&2 # shellcheck disable=SC2154 echo_debug "bat" "chargeonce_battery.not_present($_bat_str)" return 1 fi # apply temporary start threshold batdrv_chargeonce; rc=$? if [ $rc -eq 255 ]; then printf "Error: chargeonce not available for your hardware.\n" 1>&2 echo_debug "bat" "chargeonce_battery.no_supported" return 255 fi return $rc } echo_discharge_locked () { # print "locked" message echo "Error: another discharge/recalibrate operation is pending." 1>&2 return 0 } discharge_battery () { # discharge battery # $1: battery # rc: 0=ok/1=battery no present/255=no api local bat rc # select battery feature driver select_batdrv # shellcheck disable=SC2154 if [ "$_bm_dischg" = "none" ]; then # no method available --> quit echo "Error: battery discharge/recalibrate not available." 1>&2 echo_debug "bat" "discharge_battery.no_method" return 255 fi # check params if [ $# -gt 0 ]; then # parameter(s) given, check $1 bat=${1:-DEF} bat=$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]") else # no parameters given, use default(1st) battery bat=DEF fi # check bat presence and/or get default(1st) battery if ! batdrv_select_battery "$bat"; then # battery not present echo "Error: battery $bat not present." 1>&2 echo_debug "bat" "discharge_battery.not_present($bat)" return 1 fi # execute discharge batdrv_discharge; rc=$? return $rc } ukui-power-manager/3rd/tlp/func.d/25-tlp-func-rf0000664000175000017500000001145115167661430020202 0ustar fengfeng#!/bin/sh # tlp-func-rf - Radio Device Checks and PM Functions # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base # ---------------------------------------------------------------------------- # Constants readonly IW=iw readonly BLUETOOTHD=/sys/class/bluetooth # ---------------------------------------------------------------------------- # Functions # --- Wifi Device Checks get_wifi_ifaces () { # get all wifi devices -- retval: $_wifaces local wi wiu _wifaces="" for wiu in "$NETD"/*/uevent; do if grep -q -s 'DEVTYPE=wlan' "$wiu" ; then wi=${wiu%/uevent}; wi=${wi##*/} _wifaces="$_wifaces $wi" fi done _wifaces="${_wifaces# }" return 0 } get_wifi_driver () { # get driver associated with interface # $1: iface; retval: $_wifidrv local drvl _wifidrv="" if [ -d "$NETD/$1" ]; then drvl=$(readlink "$NETD/$1/device/driver") # shellcheck disable=SC2034 [ -n "$drvl" ] && _wifidrv=${drvl##*/} fi return 0 } wireless_in_use () { # check if wifi or wwan device is in use -- $1: iface if [ -f "$NETD/$1/carrier" ]; then if [ "$(read_sysf "$NETD/$1/carrier")" = "1" ]; then return 0 fi fi return 1 } any_wifi_in_use () { # check if any wifi device is in use local iface get_wifi_ifaces for iface in $_wifaces; do wireless_in_use "$iface" && return 0 done return 1 } # --- Wifi Power Management set_wifi_power_mode () { # set wifi power save mode -- $1: 0=ac mode, 1=battery mode local pwr iface if [ "$1" = "1" ]; then pwr=${WIFI_PWR_ON_BAT:-} else pwr=${WIFI_PWR_ON_AC:-} fi # check values, translate obsolete syntax case "$pwr" in off|on) ;; 0|1|N) pwr="off" ;; 2|3|4|5|6|Y) pwr="on" ;; *) pwr="" ;; # invalid input --> unconfigured esac if [ -z "$pwr" ]; then # do nothing if unconfigured echo_debug "pm" "set_wifi_power_mode($1).not_configured" return 0 fi get_wifi_ifaces if [ -z "$_wifaces" ]; then echo_debug "pm" "set_wifi_power_mode($1).no_ifaces" return 0 fi for iface in $_wifaces; do if [ -n "$iface" ]; then if cmd_exists $IW; then $IW dev "$iface" set power_save "$pwr" > /dev/null 2>&1 echo_debug "pm" "set_wifi_power_mode($1, $iface).iw: $pwr; rc=$?" else # iw not iwconfig installed echo_debug "pm" "set_wifi_power_mode($1, $iface).no_iw" return 1 fi fi done return 0 } # --- WWAN Device Checks get_wwan_ifaces () { # get all wwan devices -- retval: $_wanifaces local wi wiu _wanifaces="" for wiu in "$NETD"/*/uevent; do if grep -q -s 'DEVTYPE=wwan' "$wiu" ; then wi=${wiu%/uevent}; wi=${wi##*/} _wanifaces="$_wanifaces $wi" fi done _wanifaces="${_wanifaces# }" return 0 } any_wwan_in_use () { # check if any wwan device is in use local iface get_wwan_ifaces for iface in $_wanifaces; do wireless_in_use "$iface" && return 0 done return 1 } get_wwan_driver () { # get driver associated with interface # $1: iface; retval: $_wwandrv local drvl _wwandrv="" if [ -d "$NETD/$1" ]; then drvl=$(readlink "$NETD/$1/device/driver") # shellcheck disable=SC2034 [ -n "$drvl" ] && _wwandrv=${drvl##*/} fi return 0 } # --- Bluetooth Device Checks get_bluetooth_ifaces () { # get all bluetooth interfaces -- retval: $_bifaces # enumerate symlinks only _bifaces="$(for i in "$BLUETOOTHD"/*; do [ -h "$i" ] && echo "${i##/*/}"; done | grep -v ':')" return 0 } get_bluetooth_driver () { # get driver associated with interface -- $1: iface; retval: $_btdrv local drvl # shellcheck disable=SC2034 _btdrv="" if [ -d "$BLUETOOTHD/$1" ]; then drvl=$(readlink "$BLUETOOTHD/$1/device/driver") # shellcheck disable=SC2034 [ -n "$drvl" ] && _btdrv=${drvl##*/} fi return 0 } bluetooth_in_use () { # check if bluetooth interface is in use -- $1: iface local uev # when devices are connected to an interface its sysdir is populated with # subdevices like : where the uevent file contains a line # "DEVTYPE=link" for uev in "$BLUETOOTHD/$1/$1":*/uevent; do grep -q -s 'DEVTYPE=link' "$uev" && return 0 done return 1 } any_bluetooth_in_use () { # check if any bluetooth interface is in use local i get_bluetooth_ifaces for i in $_bifaces; do bluetooth_in_use "$i" && return 0 done return 1 } ukui-power-manager/3rd/tlp/func.d/45-tlp-func-gpu0000664000175000017500000002305215167661430020370 0ustar fengfeng#!/bin/sh # tlp-func-gpu - Intel GPU Functions # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base # ---------------------------------------------------------------------------- # Constants readonly BASE_MODD=/sys/module readonly BASE_DRMD=/sys/class/drm readonly BASE_DEBUGD=/sys/kernel/debug/dri readonly IGPU_MIN_FREQ=gt_min_freq_mhz readonly IGPU_MAX_FREQ=gt_max_freq_mhz readonly IGPU_BOOST_FREQ=gt_boost_freq_mhz # shellcheck disable=SC2034 readonly IGPU_RPN_FREQ=gt_RPn_freq_mhz # shellcheck disable=SC2034 readonly IGPU_RP0_FREQ=gt_RP0_freq_mhz # ---------------------------------------------------------------------------- # Functions # --- Intel GPU get_intel_gpu_sysdirs () { # determine Intel GPU sysdirs # $1: drm sysdir, $2: driver # retval: $_intel_gpu_parm: parameter sysdir; # $_intel_gpu_dbg: debug sysdir _intel_gpu_parm=${BASE_MODD}/$2/parameters _intel_gpu_dbg=${BASE_DEBUGD}/${1##"${BASE_DRMD}/card"} echo_debug "pm" "get_intel_gpu_sysdirs: gpu=$1 driver=$2; parm=$_intel_gpu_parm; dbg=$_intel_gpu_dbg" return 0 } set_intel_gpu_min_max_boost_freq () { # set gpu frequency limits # $1: 0=ac mode, 1=battery mode # rc: 0=ok/1=parameter error local new_min new_max new_boost local old_min old_max old_boost gpu_min gpu_max local driver suffix if [ "$1" = "1" ]; then new_min=${INTEL_GPU_MIN_FREQ_ON_BAT:-} new_max=${INTEL_GPU_MAX_FREQ_ON_BAT:-} new_boost=${INTEL_GPU_BOOST_FREQ_ON_BAT:-} suffix="BAT" else new_min=${INTEL_GPU_MIN_FREQ_ON_AC:-} new_max=${INTEL_GPU_MAX_FREQ_ON_AC:-} new_boost=${INTEL_GPU_BOOST_FREQ_ON_AC:-} suffix="AC" fi if [ -z "$new_min" ] && [ -z "$new_max" ] && [ -z "$new_boost" ]; then echo_debug "pm" "set_intel_gpu_min_max_boost_freq($1).not_configured" return 0 fi for gpu in "${BASE_DRMD}"/card?; do driver=$(readlink "${gpu}/device/driver") driver=${driver##*/} case "$driver" in i915*) # Intel GPU found get_intel_gpu_sysdirs "$gpu" "$driver" # shellcheck disable=SC2034 if old_min=$(read_sysf "$gpu/$IGPU_MIN_FREQ") \ && old_max=$(read_sysf "$gpu/$IGPU_MAX_FREQ") \ && old_boost=$(read_sysf "$gpu/$IGPU_BOOST_FREQ") \ && gpu_min=$(read_sysf "$gpu/$IGPU_RPN_FREQ") \ && gpu_max=$(read_sysf "$gpu/$IGPU_RP0_FREQ"); then # frequencies actually readable, check new ones against hardware limits and boundary conditions if ! is_uint "$new_min" 5 || [ "$new_min" -lt "$gpu_min" ] || [ "$new_min" -gt "$gpu_max" ]; then echo_message "Error in configuration at INTEL_GPU_MIN_FREQ_ON_${suffix}=\"${new_min}\": frequency invalid or out of range (see 'tlp-stat -g')." echo_debug "pm" "set_intel_gpu_min_max_boost_freq($1).invalid: gpu=$gpu min=$new_min gpu_min=$gpu_min hw_max=$gpu_max; rc=1" return 1 elif ! is_uint "$new_max" 5 || [ "$new_max" -lt "$gpu_min" ] || [ "$new_max" -gt "$gpu_max" ]; then echo_message "Error in configuration at INTEL_GPU_MAX_FREQ_ON_${suffix}=\"${new_max}\": frequency invalid or out of range (see 'tlp-stat -g')." echo_debug "pm" "set_intel_gpu_min_max_boost_freq($1).invalid: gpu=$gpu min=$new_min gpu_min=$gpu_min gpu_max=$gpu_max; rc=1" return 1 elif ! is_uint "$new_boost" 5 || [ "$new_boost" -lt "$gpu_min" ] || [ "$new_boost" -gt "$gpu_max" ]; then echo_message "Error in configuration at INTEL_GPU_BOOST_FREQ_ON_${suffix}=\"${new_boost}\": frequency invalid or out of range (see 'tlp-stat -g')." echo_debug "pm" "set_intel_gpu_min_max_boost_freq($1).invalid: gpu=$gpu boost=$new_boost gpu_min=$gpu_min gpu_max=$gpu_max; rc=1" return 1 elif [ "$new_min" -gt "$new_max" ]; then echo_message "Error in configuration: INTEL_GPU_MIN_FREQ_ON_${suffix} > INTEL_GPU_MAX_FREQ_ON_${suffix}." echo_debug "pm" "set_intel_gpu_min_max_boost_freq($1).min_gt_max: gpu=$gpu min=$new_min max=$new_max; rc=1" return 1 elif [ "$new_max" -gt "$new_boost" ]; then echo_message "Error in configuration: INTEL_GPU_MAX_FREQ_ON_${suffix} > INTEL_GPU_BOOST_FREQ_ON_${suffix}." echo_debug "pm" "set_intel_gpu_min_max_boost_freq($1).max_gt_boost: gpu=$gpu max=$new_max boost=$new_boost; rc=1" return 1 fi # all parameters valid --> write min, max in proper sequence if [ "$new_min" -gt "$old_max" ]; then write_sysf "$new_max" "$gpu/$IGPU_MAX_FREQ" echo_debug "pm" "set_intel_gpu_min_max_boost_freq($1).max: gpu=$gpu freq=$new_max; rc=$?" write_sysf "$new_min" "$gpu/$IGPU_MIN_FREQ" echo_debug "pm" "set_intel_gpu_min_max_boost_freq($1).min: gpu=$gpu freq=$new_min; rc=$?" else write_sysf "$new_min" "$gpu/$IGPU_MIN_FREQ" echo_debug "pm" "set_intel_gpu_min_max_boost_freq($1).min: gpu=$gpu freq=$new_min; rc=$?" write_sysf "$new_max" "$gpu/$IGPU_MAX_FREQ" echo_debug "pm" "set_intel_gpu_min_max_boost_freq($1).max: gpu=$gpu freq=$new_max; rc=$?" fi write_sysf "$new_boost" "$gpu/$IGPU_BOOST_FREQ" echo_debug "pm" "set_intel_gpu_min_max_boost_freq($1).boost: gpu=$gpu freq=$new_boost; rc=$?" else echo_debug "pm" "set_intel_gpu_min_max_boost_freq($1).not_available: gpu=$gpu" fi esac done return 0 } # --- AMD Radeon GPU set_amdgpu_profile () { # set amdgpu/radeon power profile # $1: 0=ac mode, 1=battery mode local driver gpu level pwr rc1 rc2 local sdone=0 # 1=gpu present for gpu in "${BASE_DRMD}"/card?; do driver=$(readlink "${gpu}/device/driver") driver=${driver##*/} case "$driver" in amdgpu) if [ -f "$gpu/device/power_dpm_force_performance_level" ]; then # Use amdgpu dynamic power management method (DPM) if [ "$1" = "1" ]; then level=${RADEON_DPM_PERF_LEVEL_ON_BAT:-} else level=${RADEON_DPM_PERF_LEVEL_ON_AC:-} fi if [ -z "$level" ]; then # do nothing if unconfigured echo_debug "pm" "set_amdgpu_profile($1).amdgpu.not_configured: gpu=$gpu" return 0 else write_sysf "$level" "$gpu/device/power_dpm_force_performance_level"; rc1=$? echo_debug "pm" "set_amdgpu_profile($1).amdgpu: gpu=$gpu level=${level}: rc=$rc1" fi sdone=1 fi ;; radeon) if [ -f "$gpu/device/power_dpm_force_performance_level" ] && [ -f "$gpu/device/power_dpm_state" ]; then # Use radeon dynamic power management method (DPM) if [ "$1" = "1" ]; then level=${RADEON_DPM_PERF_LEVEL_ON_BAT:-} pwr=${RADEON_DPM_STATE_ON_BAT:-} else level=${RADEON_DPM_PERF_LEVEL_ON_AC:-} pwr=${RADEON_DPM_STATE_ON_AC:-} fi if [ -z "$pwr" ] || [ -z "$level" ]; then # do nothing if (partially) unconfigured echo_debug "pm" "set_amdgpu_profile($1).radeon.not_configured: gpu=$gpu" return 0 else write_sysf "$level" "$gpu/device/power_dpm_force_performance_level"; rc1=$? write_sysf "$pwr" "$gpu/device/power_dpm_state"; rc2=$? echo_debug "pm" "set_amdgpu_profile($1).radeon: gpu=$gpu perf=${level}: rc=$rc1; state=${pwr}: rc=$rc2" fi sdone=1 elif [ -f "$gpu/device/power_method" ] && [ -f "$gpu/device/power_profile" ]; then # Use legacy radeon power profile method if [ "$1" = "1" ]; then pwr=${RADEON_POWER_PROFILE_ON_BAT:-} else pwr=${RADEON_POWER_PROFILE_ON_AC:-} fi if [ -z "$pwr" ]; then # do nothing if unconfigured echo_debug "pm" "set_amdgpu_profile($1).radeon_legacy.not_configured: gpu=$gpu" return 0 else write_sysf "profile" "$gpu/device/power_method"; rc1=$? write_sysf "$pwr" "$gpu/power_profile"; rc2=$? echo_debug "pm" "set_amdgpu_profile($1).radeon_legacy: gpu=$gpu method=profile: rc=$rc1; profile=${pwr}: rc=$rc2" fi sdone=1 fi ;; esac done if [ $sdone -eq 0 ]; then echo_debug "pm" "set_amdgpu_profile($1).no_gpu" fi return 0 } ukui-power-manager/3rd/tlp/tlp0000775000175000017500000003701015167661430015245 0ustar fengfeng#!/bin/sh # tlp - adjust power settings # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # --- Source libraries for lib in /usr/share/ukui-power-manager/tlp/tlp-func-base /usr/share/ukui-power-manager/tlp/func.d/[0-9][0-9]*; do # shellcheck disable=SC1090 . "$lib" || exit 70 done # --- Constants # --- Subroutines apply_common_settings () { # apply settings common to all modes # $1: 0=ac mode, 1=battery mode set_laptopmode "$1" set_dirty_parms "$1" set_platform_profile "$1" set_cpu_driver_opmode "$1" set_cpu_scaling_governor "$1" set_cpu_scaling_min_max_freq "$1" set_intel_cpu_perf_pct "$1" set_cpu_boost_all "$1" set_cpu_dyn_boost "$1" set_cpu_perf_policy "$1" set_nmi_watchdog set_mem_sleep "$1" set_ahci_port_runtime_pm "$1" set_runtime_pm "$1" set_ahci_disk_runtime_pm "$1" set_sata_link_power "$1" set_disk_apm_level "$1" set_disk_spindown_timeout "$1" set_disk_iosched set_pcie_aspm "$1" set_intel_gpu_min_max_boost_freq "$1" set_amdgpu_profile "$1" set_wifi_power_mode "$1" disable_wake_on_lan set_sound_power_mode "$1" return 0 } apply_suspend_settings () { # apply settings before suspending set_ahci_port_runtime_pm "2" set_ahci_disk_runtime_pm "2" set_pcie_aspm "2" return 0 } show_usage () { echo "Usage: tlp start|true|bat|false|ac|usb|bayoff|chargeonce|discharge|setcharge|fullcharge|recalibrate|diskid" 1>&2 } parse_args () { # parse command-line arguments # $@: arguments to parse # retval: $_cmd: command; # $_cmd2: subcommand; # $_carg1, # $_carg2, # $_carg3: command arguments # parsing control: 'nil' means that the element is still expected _cmd="nil" _cmd2="nil" _carg1="nil" _carg2="nil" _carg3="nil" # iterate arguments until exhausted or delimiter '--' reached while [ $# -gt 0 ]; do if [ "$1" = "--" ]; then break; elif [ "$_cmd" = "nil" ]; then # command case "$1" in ac|auto|bat|bayoff|false|diskid|resume|suspend|start|true|usb) # commands without further arguments _cmd="$1" _cmd2="" _carg1="" _carg2="" _carg3="" ;; chargeonce|discharge|fullcharge|recalibrate) # commands with one or no arguments _cmd="$1" _cmd2="" _carg2="" _carg3="" ;; setcharge) # command with up to three arguments _cmd="$1" _cmd2="" ;; init) # command with subcommand and no arguments _cmd="$1" _carg1="" _carg2="" _carg3="" ;; stat) # unsupported command echo "Error: 'tlp stat' no longer supported, use 'tlp-stat' instead." 1>&2 do_exit 3 ;; noop) # no operation _cmd="$1" _cmd2="" ;; --version) # no operation _cmd="version" _cmd2="" ;; *) # unknown command echo "Error: unknown command \"$1\"." 1>&2 show_usage do_exit 3 ;; esac elif [ "$_cmd2" = "nil" ]; then # subcommand case "$1" in start|stop|restart|force-reload) _cmd2="$1" ;; *) # unknown subcommand echo "Usage: tlp init {start|stop|restart|force-reload}" >&2 do_exit 3 ;; esac elif [ "$_carg1" = "nil" ]; then # first command argument _carg1="$1" elif [ "$_carg2" = "nil" ]; then # second command argument _carg2="$1" elif [ "$_carg3" = "nil" ]; then # third command argument _carg3="$1" fi shift # next argument done # while arguments if [ "$_cmd" = "nil" ]; then # no command parsed show_usage do_exit 3 fi # clear missing arguments [ "$_carg1" = "nil" ] && _carg1="" [ "$_carg2" = "nil" ] && _carg2="" [ "$_carg3" = "nil" ] && _carg3="" return 0 } # --- MAIN parse_args "$@" if [ "$_cmd" = "version" ]; then print_version exit 0 fi # read configuration: quit on error, trace allowed read_config 1 0 parse_args4config "$@" check_tlp_enabled 1 || do_exit 1 add_sbin2path check_laptop_mode_tools if [ -z "$_cmd2" ]; then echo_debug "run" "+++ $_cmd ($TLPVER) ++++++++++++++++++++++++++++++++++++++++" else echo_debug "run" "+++ $_cmd $_cmd2 ($TLPVER) ++++++++++++++++++++++++++++++++++++++++" fi # shellcheck disable=SC2154 if [ -n "$_addpath" ]; then # shellcheck disable=SC2154 echo_debug "path" "PATH=${_oldpath}[${_addpath}]" else # shellcheck disable=SC2154 echo_debug "path" "PATH=${_oldpath}" fi echo_debug "run" "SHELL=$(print_shell); umask=$(umask)" # get current power state get_power_mode "$_cmd"; pwrmode=$? get_manual_mode # determine new power state case "$_cmd" in init|start) # discard manual mode clear_manual_mode ;; auto|resume) # if manual mode is set, use instead of current power state # shellcheck disable=SC2154 case $_manual_mode in 0|1) pwrmode="$_manual_mode" ;; esac ;; true|bat) pwrmode=1 set_manual_mode 1 ;; false|ac) pwrmode=0 set_manual_mode 0 ;; esac # shellcheck disable=SC2154 case "$_syspwr" in 0) echo_debug "run" "power_source=ac" ;; 1) echo_debug "run" "power_source=bat" ;; *) echo_debug "run" "power_source=unknown ($_syspwr)" ;; esac echo_debug "run" "manual_mode=$_manual_mode" case "$pwrmode" in 0) echo_debug "run" "power_mode=ac" ;; 1) echo_debug "run" "power_mode=bat" ;; *) echo_debug "run" "power_mode=unknown ($pwrmode)" ;; esac # process command exitcode=0 case "$_cmd" in init) # system initialization/shutdown: sysv, upstart, systemd, ... check_root # try to obtain lock (with timeout) locked=0 if lock_tlp; then locked=1 else echo "Failed to get lock, continuing anyway." 1>&2 fi # do init business ... # shellcheck disable=SC2034 _bgtask=1 case "$_cmd2" in start) # apply power save settings compare_and_save_power_state "$pwrmode" echo -n "Applying power save settings..." apply_common_settings "$pwrmode" poweroff_drivebay "$pwrmode" 0 [ "$X_TLP_USB_MODE" = "1" ] && set_usb_suspend 0 auto echo "done." # apply battery settings echo -n "Setting battery charge thresholds..." init_batteries_thresholds echo "done." # apply radio states set_radio_device_states start ;; restart|force-reload) # apply power save settings compare_and_save_power_state "$pwrmode" echo -n "Applying power save settings..." apply_common_settings "$pwrmode" poweroff_drivebay "$pwrmode" 0 [ "$X_TLP_USB_MODE" = "1" ] && set_usb_suspend 0 auto echo "done." # apply battery settings echo -n "Setting battery charge thresholds..." init_batteries_thresholds echo "done." ;; stop) # remove usb startup flag [ -f "$USB_DONE" ] && rm "$USB_DONE" # clear saved power state clear_saved_power_state if [ "$X_TLP_SHUTDOWN_ACMODE" = "1" ]; then # workaround (optional): apply ac settings echo -n "Applying power save settings..." apply_common_settings 0 poweroff_drivebay "$pwrmode" 0 echo "done." fi # apply radio states set_radio_device_states stop ;; *) echo "Usage: tlp init {start|stop|restart|force-reload}" >&2 do_exit 3 ;; esac save_runconf # unlock if necessary [ $locked -eq 0 ] || unlock_tlp ;; auto) # set mode depending on state (called by udev rule) # -- but only if not previously run for the same power state # rationale: filter out duplicate power_supply udev events check_root # shellcheck disable=SC2034 _bgtask=1 check_services_activation_status if lock_tlp_nb; then if compare_and_save_power_state "$pwrmode"; then apply_common_settings "$pwrmode" poweroff_drivebay "$pwrmode" 0 set_radio_device_states "$pwrmode" if [ "$RESTORE_THRESHOLDS_ON_BAT" = "1" ] \ && [ "$pwrmode" = "1" ]; then init_batteries_thresholds fi save_runconf fi unlock_tlp fi ;; start) # set mode depending on state (interactive mode) check_services_activation_status check_root if lock_tlp; then compare_and_save_power_state "$pwrmode" apply_common_settings "$pwrmode" poweroff_drivebay "$pwrmode" 0 set_usb_suspend 0 auto init_batteries_thresholds set_radio_device_states "$pwrmode" save_runconf unlock_tlp echo_started_mode "$pwrmode" else echo_tlp_locked fi ;; true|bat) # set battery power mode check_services_activation_status check_root if lock_tlp; then compare_and_save_power_state 1 apply_common_settings 1 poweroff_drivebay "$pwrmode" 0 [ "$X_TLP_USB_MODE" = "1" ] && set_usb_suspend 0 auto set_radio_device_states 1 save_runconf unlock_tlp echo_started_mode 1 else echo_tlp_locked fi ;; false|ac) # set ac power mode check_services_activation_status check_root if lock_tlp; then compare_and_save_power_state 0 apply_common_settings 0 poweroff_drivebay "$pwrmode" 0 [ "$X_TLP_USB_MODE" = "1" ] && set_usb_suspend 0 auto set_radio_device_states 0 save_runconf unlock_tlp echo_started_mode 0 else echo_tlp_locked fi ;; suspend) # handle suspend/hibernate check_root save_device_states "bluetooth wwan" suspend_drivebay "$pwrmode" case "$X_TLP_SUSPEND_ACMODE" in 1) # workaround (optional): apply ac settings if lock_tlp; then apply_common_settings 0 save_runconf unlock_tlp fi ;; 0) # workaround disabled: do nothing ;; *) # workaround (default): apply selected settings to avoid freezes on wakeup if lock_tlp; then apply_suspend_settings save_runconf unlock_tlp fi ;; esac ;; resume) # handle resume check_root if lock_tlp; then restore_device_states compare_and_save_power_state "$pwrmode" apply_common_settings "$pwrmode" resume_drivebay "$pwrmode" init_batteries_thresholds "asus huawei lg lg-legacy" save_runconf unlock_tlp fi ;; usb) # Enable usb autosuspend check_root set_usb_suspend 1 auto ;; bayoff) # power off drive bay check_root poweroff_drivebay "$pwrmode" 1 ;; setcharge) # set charge thresholds (temporarily) check_root # quoting args will break $# in setcharge_battery() # shellcheck disable=SC2086 setcharge_battery $_carg1 $_carg2 $_carg3 exitcode=$? ;; fullcharge) # charge battery to 100% (temporarily) if check_ac_power fullcharge; then check_root # quoting args will break $# in setcharge_battery() # shellcheck disable=SC2086 setcharge_battery DEF DEF $_carg1 exitcode=$? if [ $exitcode -eq 0 ]; then echo "Charging starts now, keep AC connected." fi else exitcode=2 fi ;; chargeonce) # charge battery to stop threshold once if check_ac_power chargeonce; then check_root # quoting args will break $# in chargeonce_battery() # shellcheck disable=SC2086 chargeonce_battery $_carg1 exitcode=$? if [ $exitcode -eq 0 ]; then echo "Charging starts now, keep AC connected." fi else exitcode=2 fi ;; discharge) # discharge battery completely (to recalibrate) if check_ac_power discharge; then check_root if lock_tlp_nb tlp_discharge; then # quoting args will break $# in discharge_battery() # shellcheck disable=SC2086 discharge_battery $_carg1 exitcode=$? else echo_discharge_locked fi else exitcode=2 fi ;; recalibrate) # recalibrate battery, i.e. discharge and charge to 100% if check_ac_power recalibrate; then check_root if lock_tlp_nb tlp_discharge; then if setcharge_battery DEF DEF "$_carg1" "/discharge/recalibrate"; then sleep 1 # quoting args will break $# in discharge_battery() # shellcheck disable=SC2086 discharge_battery $_carg1 exitcode=$? if [ $exitcode -eq 0 ]; then echo "Charging starts now, for a complete recalibration" echo "keep AC connected until the battery is fully charged." else echo "Battery recalibration aborted." fi fi else echo_discharge_locked fi else exitcode=2 fi ;; diskid) # show disk id's show_disk_ids ;; noop) # Debug: no operation check_root select_batdrv batdrv_select_battery "DEF" save_runconf echo "Debug: no operation performed." ;; esac do_exit $exitcode ukui-power-manager/3rd/tlp/tlp-readconfs0000775000175000017500000001771615167661430017222 0ustar fengfeng#!/usr/bin/perl # tlp-readconfs - read all of TLP's config files # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Cmdline options # --outfile : filepath to contain merged configuration # --notrace: disable trace # --cdiff: only show differences to the default # # Return codes # 0: ok # 5: tlp.conf missing # 6: defaults.conf missing package tlp_readconfs; use strict; use warnings; # --- Modules use File::Basename; use Getopt::Long; # --- Constants use constant CONF_USR => "/usr/share/ukui-power-manager/tlp/tlp.conf"; use constant CONF_DIR => "/usr/share/ukui-power-manager/tlp/tlp.d"; use constant CONF_DEF => "/usr/share/ukui-power-manager/tlp/defaults.conf"; use constant CONF_REN => "/usr/share/ukui-power-manager/tlp/rename.conf"; use constant CONF_DPR => "/usr/share/ukui-power-manager/tlp/deprecated.conf"; use constant CONF_OLD => "/etc/default/tlp"; # Exit codes use constant EXIT_TLPCONF => 5; use constant EXIT_DEFCONF => 6; # --- Global vars my @config_val = (); # 2-dim array: parameter name, value, source, default-value my %config_idx = (); # hash: parameter name => index into the name-value array my %rename = (); # hash: OLD_PARAMETER => NEW_PARAMETER my $renrex; # compiled regex for renaming parameters my $do_rename = 0; # enable renaming (when $renrex not empty) my %dprmsg = (); # hash: PARAMETER => deprecated message my $notrace = 0; my $debug = 0; my $cdiff = 0; my $outfile; my $defsrc = basename (CONF_DEF); # --- Subroutines # Format and write debug message # @_: printf arguments including format string sub printf_debug { if ( ! $notrace && $debug ) { open (my $logpipe, "|-", "logger -p debug -t \"tlp\" --id=\$\$ --") || return 1; printf {$logpipe} @_; close ($logpipe); } return 0; } # Store parameter name, value, source in array/hash # $_[0]: parameter name (non-null string) # $_[1]: parameter value (maybe null string) # $_[2]: 0=replace/1=append parameter value # $_[3]: parameter source e.g. filepath + line no. # $_[4]: 0=user config/1=default # return: 0=new name/1=known name sub store_name_value_source { my $name = $_[0]; my $value = $_[1]; my $append = $_[2]; my $source = $_[3]; my $is_def = $_[4]; $debug = 1 if ( $name eq "TLP_DEBUG" && $value =~ /\bcfg\b/ ); if ( defined $config_idx{$name} ) { # existing name if ( $append ) { # append value, source $config_val[$config_idx{$name}][1] .= " $value"; $config_val[$config_idx{$name}][2] .= " & $source"; } else { # replace value, source $config_val[$config_idx{$name}][1] = $value; $config_val[$config_idx{$name}][2] = $source; } printf_debug ("tlp-readconfs.replace [%s]: %s=\"%s\" %s\n", $config_idx{$name}, $name, $value, $source); } else { # new name --> store name, value, source and hash name if ( $is_def ) { #save value as default push(@config_val, [$name, $value, $source, $value]); } else { # save value as user config push(@config_val, [$name, $value, $source, ""]); } $config_idx{$name} = $#config_val; printf_debug ("tlp-readconfs.insert [%s]: %s=\"%s\" %s\n", $#config_val, $name, $value, $source); } return 0; } # Parse whole config file and store parameters # $_[0]: filepath # $_[1]: 0=no change/1=rename parameters # return: 0=ok/1=file non-existent sub parse_configfile { my $fname = $_[0]; my $do_ren = $_[1]; my $source; my $is_def; if ( $fname eq CONF_DEF ) { $source = $defsrc; $is_def = 1; } else { $source = $fname; $is_def = 0; } open (my $cf, "<", $fname) || return 1; my $ln = 0; while ( my $line = <$cf> ) { # strip newline chomp $line; $ln += 1; # strip comments: everything after '#' but not when '#' is quoted, i.e. followed by a closing quote ('"') # note: opening quote is handled by the regex below $line =~ s/#(?=[^"]*$).*$//; # strip trailing spaces $line =~ s/\s+$//; # select lines with format 'PARAMETER=value' or 'PARAMETER="value"' if ( $line =~ /^(?[A-Z_]+[0-9]*)(?(=|\+=))(?:(?[-0-9a-zA-Z _.:]*)|"(?[-0-9a-zA-Z _.:]*)")\s*$/ ) { my $name = $+{name}; if ( $do_ren ) { # rename PARAMETER $name =~ s/$renrex/$rename{$1}/; } my $value = $+{val_dquoted} // $+{val_bare}; my $append = $+{op} eq "+="; store_name_value_source ($name, $value, $append, $source . " L" . sprintf ("%04d", $ln), $is_def ); } } close ($cf); return 0; } # Output all stored parameter name, value to a file # or parameter name, value, source to stdout # $_[0]: filepath (without argument the output will be written to stdout) # return: 0=ok/1=file open error sub write_runconf { my $fname = $_[0]; my $runconf; if ( ! $fname ) { $runconf = *STDOUT; } else { open ($runconf, ">", $fname) || return 1; } foreach ( @config_val ) { my ($name, $value, $source, $default) = @$_; if ( $runconf eq *STDOUT ) { my $msg = ""; # stdout: check for deprecated message if ( defined $dprmsg{$name} ) { $msg = " #! $dprmsg{$name}"; } # --cdiff: do not show user config lines matching the default if ( ! $cdiff || $value ne $default ) { printf {$runconf} "%s: %s=\"%s\"%s\n", $source, $name, $value, $msg; } } else { printf {$runconf} "%s=\"%s\"\n", $name, $value; } } close ($runconf); return 0 } # Parse parameter renaming rules from file # $_[0]: rules file # return: 0=ok/1=file non-existent sub parse_renfile { my $fname = $_[0]; open (my $rf, "<", $fname) || return 1; # accumulate renaming while ( my $line = <$rf> ) { chomp $line; # select lines with format 'OLD_PARAMETERNEW_PARAMETER' if ( $line =~ /^(?[A-Z_]+[0-9]*)\s+(?[A-Z_]+[0-9]*)\s*$/ ) { my $old_name = $+{old_name}; my $new_name = $+{new_name}; $rename{$old_name} = $new_name; } } close ($rf); if ( keys %rename > 0 ) { # renaming hash not empty --> compile OLD_PARAMETER keys to match regex $renrex = qr/^(@{[join '|', map { quotemeta($_) } keys %rename]})$/; # enable renaming $do_rename = 1; } return 0; } # Parse deprecated parameters and messages from file # $_[0]: parameters file # return: 0=ok/1=file non-existent sub parse_dprfile { my $fname = $_[0]; open (my $df, "<", $fname) || return 1; # accumulate deprecated params and mesgs while ( my $line = <$df> ) { chomp $line; # select lines with format 'PARAMETER# message' if ( $line =~ /^(?[A-Z_]+[0-9]*)\s+#\s+(?.*)$/ ) { my $param_name = $+{param_name}; my $param_msg = $+{param_msg}; $dprmsg{$param_name} = $param_msg; } } close ($df); return 0; } # --- MAIN # parse arguments GetOptions ('outfile=s' => \$outfile, 'notrace' => \$notrace, 'cdiff' => \$cdiff); # read parameter renaming rules parse_renfile (CONF_REN); # read deprecated parameter messages parse_dprfile (CONF_DPR); # 1. read intrinsic defaults (no renaming) parse_configfile (CONF_DEF, 0) == 0 || exit EXIT_DEFCONF; # 2. read customization (with renaming) foreach my $conffile ( grep { -f } glob CONF_DIR . "/*.conf" ) { parse_configfile ($conffile, $do_rename); } # 3. read user settings (with renaming) # parse_configfile (CONF_USR, $do_rename) == 0 # || parse_configfile (CONF_OLD, $do_rename) == 0 || exit EXIT_TLPCONF; # save result write_runconf ($outfile); exit 0; ukui-power-manager/3rd/tlp/get_tlp_bat_paths.sh0000775000175000017500000000133215167661430020540 0ustar fengfeng#!/bin/bash test_root () { # test root privilege -- rc: 0=root, 1=not root [ "$(id -u)" = "0" ] } check_root () { # show error message and quit when root privilege missing if ! test_root; then echo "Error: missing root privilege." 1>&2 exit 1 fi } check_root if [ -f "/usr/share/ukui-power-manager/tlp/origin_tmp.conf" ]; then rm "/usr/share/ukui-power-manager/tlp/origin_tmp.conf" fi UPM_TLP_FLAG=ONLY_ECHO_PATH /usr/share/ukui-power-manager/tlp/tlp bat &> /dev/null sort -u "/usr/share/ukui-power-manager/tlp/origin_tmp.conf" > "/usr/share/ukui-power-manager/tlp/origin.conf" rm "/usr/share/ukui-power-manager/tlp/origin_tmp.conf" cat "/usr/share/ukui-power-manager/tlp/origin.conf" ukui-power-manager/3rd/tlp/bat.d/0000775000175000017500000000000015167661430015507 5ustar fengfengukui-power-manager/3rd/tlp/bat.d/35-lg0000664000175000017500000004265215167661430016272 0ustar fengfeng#!/bin/sh # lg - Battery Plugin for LG laptops w/ lg_laptop driver # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat # --- Hardware Detection readonly BATDRV_LG_MD=/sys/devices/platform/lg-laptop batdrv_is_lg () { # check if kernel module loaded # rc: 0=LG, 1=other hardware [ -d $BATDRV_LG_MD ] } # --- Plugin API functions batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $batdrv_kmod # # 1. check for vendor specific kernel api # --> retval $_natacpi: # 0=thresholds/ # 32=disabled/ # 128=no kernel support/ # 254=laptop not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi # # 3. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 4. define battery care limit config, sysfile and default # config suffix (BAT0) --> retval $_bt_cfg_bat, # sysfile --> retval $_bf_stop, # default --> retval $_bt_def_stop; _batdrv_plugin="lg" _batdrv_kmod="lg_laptop" # kernel module for natacpi # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! batdrv_is_lg; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_match" return 1 fi fi # presume no features at all _natacpi=128 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _batteries="" _bt_cfg_bat="BAT0" # all batteries share the BAT0 config parameter _bf_stop="" _bt_def_stop=100 # iterate batteries local bd bs sp local done=0 for bd in "$ACPIBATDIR"/CMB[01] "$ACPIBATDIR"/BAT[01]; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi # skip natacpi detection for 2nd and subsequent batteries [ $done -eq 1 ] && continue if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 elif sp="$(read_sysf "$bd/charge_control_end_threshold")"; then # sysfile for stop threshold exists and is actually readable if [ "$sp" != "0" ]; then # threshold is non-zero _natacpi=0 _bm_thresh="natacpi" _bn_stop="charge_control_end_threshold" else # zero means laptop not supported via the kernel driver _natacpi=254 fi elif [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then # simulate api _natacpi=0 _bm_thresh="natacpi" _bn_stop="charge_control_end_threshold" else # nothing detected _natacpi=254 fi fi done if [ $_natacpi -ge 32 ]; then # let's probe lg-legacy next (kernel 5.17 and older) echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_natacpi: batteries=$_batteries; natacpi=$_natacpi" return 1 fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; thresh=$_bm_thresh; bf_stop=$_bf_stop" return 0 } batdrv_select_battery () { # determine battery acpidir # $1: BAT0/BAT1/CMB0/CMB1/DEF # global params: $_batdrv_plugin, $_batteries, $_bm_thresh, $_bn_stop # # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0/BAT1/CMB0/CMB1; # $_bf_stop: sysfile for stop threshold # $_bd_read: directory with battery data sysfiles; # prerequisite: batdrv_init() # defaults _bat_str="" # no bat _bd_read="" # no directory local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]")" # validate battery param case "$bat" in DEF) # 1st battery is default _bat_str="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then _bat_str="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # determine natacpi sysfile _bd_read="$ACPIBATDIR/$_bat_str" if [ "$_bm_thresh" = "natacpi" ]; then _bf_stop="$ACPIBATDIR/$_bat_str/$_bn_stop" fi echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; bd_read=$_bd_read; bf_stop=$_bf_stop" return 0 } batdrv_read_threshold () { # read and print charge threshold (stop only) # global params: $_batdrv_plugin, $_bm_thresh, $_bf_stop # out: threshold 80,100/"" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local out="" rc=0 out="$X_THRESH_SIMULATE_STOP" if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold.simulate: bf_stop=$_bf_stop; out=$out; rc=$rc" return 0 fi if [ "$_bm_thresh" = "natacpi" ]; then if ! out=$(read_sysf "$_bf_stop"); then # not readable/non-existent if [ "$1" != "1" ]; then out="" else out="(not available)" fi rc=4 fi else # no threshold api if [ "$1" = "1" ]; then out="(not available)" fi rc=255 fi # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else if [ "$1" = "1" ]; then printf "(not available)\n" fi rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold: bf_stop=$_bf_stop; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write charge thresholds for a battery # use pre-determined method and sysfiles from global parms # $1: new start threshold -- unused dummy for plugin api compatibility # $2: new stop threshold 80/100/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bat_str, $_bt_cfg_bat, $_bf_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold out of range or non-numeric/ # 4=threshold read error/ # 5=threshold write error/ # 6=threshold write discarded by kernel or firmware # prerequisite: batdrv_init(), batdrv_select_battery() local new_stop=${2:-} local verb=${3:-0} local old_stop # insert defaults [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds local rc if [ -n "$4" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # stop: check for 3 digits max, ensure 80 or 100 if ! is_uint "$new_stop" 3 || ! wordinlist "$new_stop" "80 100"; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": not specified or invalid (must be 80 or 100). Skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": not specified or invalid (must be 80 or 100). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: stop charge threshold (%s) not specified or invalid (must be 80 or 100). Aborted.\n" "$new_stop" 1>&2 fi ;; esac return 2 fi # read active stop threshold value if ! old_stop=$(batdrv_read_threshold); then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).read_error: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) echo_message "Error: could not read current stop charge threshold. Skipped." ;; 2) printf "Error: could not read current stop charge threshold. Aborted.\n" 1>&2 ;; esac return 4 fi # write new threshold if [ "$verb" = "2" ]; then printf "Setting temporary charge threshold for %s:\n" "$_bat_str" fi local rc=0 if [ "$old_stop" != "$new_stop" ]; then # new threshold differs from effective one --> write it if write_sysf "$new_stop" "$_bf_stop"; then if [ "$(read_sysf "$_bf_stop")" != "$new_stop" ]; then # write discarded by kernel or firmware rc=6 fi else # write error rc=5 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).write: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop; rc=$rc" case $verb in 2) if [ $rc -eq 0 ]; then printf " stop = %d\n" "$new_stop" else printf " stop = %d (Error: write failed)\n" "$new_stop" 1>&2 fi ;; 1) if [ $rc -gt 0 ]; then echo_message "Error: writing stop charge threshold failed." fi ;; esac else echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).no_change: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop" if [ "$verb" = "2" ]; then printf " stop = %d (no change)\n" "$new_stop" fi fi return $rc } batdrv_chargeonce () { # function not implemented for LG laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.charge_once.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # apply configured stop thresholds from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local bat stop_thresh for bat in CMB0 CMB1 BAT0 BAT1; do if batdrv_select_battery "$bat"; then eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "DEF" "$stop_thresh" 1 1; rc=$? fi done return 0 } batdrv_read_force_discharge () { # function not implemented for LG laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge.not_implemented" return 255 } batdrv_write_force_discharge () { # function not implemented for LG laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented for LG laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented for LG laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented for LG laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_bm_thresh, $_natacpi, $_bd_read, $_bf_stop # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" if [ "$_bm_thresh" = "natacpi" ]; then printf "Supported features: charge threshold\n" else printf "Supported features: none available\n" fi printf "Driver usage:\n" # vendor specific kernel api case $_natacpi in 0) printf "* natacpi (%s) = active (charge threshold)\n" "$_batdrv_kmod" ;; 32) printf "* natacpi (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* natacpi (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* natacpi (%s) = inactive (laptop not supported)\n" "$_batdrv_kmod" ;; *) printf "* natacpi (%s) = unknown status\n" "$_batdrv_kmod" ;; esac if [ "$_bm_thresh" = "natacpi" ]; then printf "Parameter value range:\n" printf "* STOP_CHARGE_THRESH_BAT0: 80(on), 100(off)\n" fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi # --- show battery features: thresholds if [ "$_bm_thresh" = "natacpi" ]; then printf "%-59s = %6s [%%]\n" "$_bf_stop" "$(batdrv_read_threshold 1)" printf "\n" fi # --- show charge level (SOC) and capacity if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # no recommendations for LG laptops return 0 } ukui-power-manager/3rd/tlp/bat.d/36-lg-legacy0000664000175000017500000004046515167661430017535 0ustar fengfeng#!/bin/sh # lg-legacy - Battery Plugin for LG laptops w/ lg_laptop driver provided # by kernel 5.17 or older (see plugin 'lg' for newer kernels) # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat, 35-lg # --- Hardware Detection: function provided by 35-lg # --- Plugin API functions readonly BATDRV_LG_BCL="${BATDRV_LG_MD}/battery_care_limit" batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $batdrv_kmod # # 1. check for vendor specific kernel api # --> retval $_natacpi: # 0=thresholds/ # 32=disabled/ # 128=no kernel support/ # 254=laptop not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi # # 3. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 4. define battery care limit config, sysfile and default # config suffix --> retval $_bt_cfg_bat, # sysfile --> retval $_bf_stop, # default --> retval $_bt_def_stop; _batdrv_plugin="lg-legacy" _batdrv_kmod="lg_laptop" # kernel module for natacpi # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! batdrv_is_lg; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_match" return 1 fi fi # presume no features at all _natacpi=128 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _batteries="" _bt_cfg_bat="BAT0" # all batteries share the BAT0 config parameter _bf_stop="" _bt_def_stop=100 # iterate batteries local bd bs for bd in "$ACPIBATDIR"/CMB[01] "$ACPIBATDIR"/BAT[01]; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi fi done # check for vendor specific kernel api if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 elif sp="${X_THRESH_SIMULATE_STOP:-$(read_sysf "$BATDRV_LG_BCL")}"; then # sysfile exists and is actually readable --> check threshold value if [ "$sp" != "0" ]; then # threshold is non-zero _natacpi=0 _bm_thresh="natacpi" _bf_stop="$BATDRV_LG_BCL" else # zero means laptop not supported via the kernel driver _natacpi=254 fi elif [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then # simulate api _natacpi=0 _bm_thresh="natacpi" _bf_stop="$BATDRV_LG_BCL" else # nothing detected _natacpi=254 fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; thresh=$_bm_thresh; bf_stop=$_bf_stop" return 0 } batdrv_select_battery () { # determine battery acpidir # $1: BAT0/BAT1/CMB0/CMB1/DEF # global params: $_batdrv_plugin, $_batteries # # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0/BAT1/CMB0/CMB1; # $_bd_read: directory with battery data sysfiles; # prerequisite: batdrv_init() # defaults _bat_str="" # no bat _bd_read="" # no directory local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]")" # validate battery param case "$bat" in DEF) # 1st battery is default _bat_str="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then _bat_str="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # determine battery directory _bd_read="$ACPIBATDIR/$_bat_str" echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; bd_read=$_bd_read;" return 0 } batdrv_read_threshold () { # read and print charge threshold (stop only) # global params: $_batdrv_plugin, $_bm_thresh, $_bf_stop # out: threshold 80,100/"" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local out="" rc=0 out="$X_THRESH_SIMULATE_STOP" if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold.simulate: bf_stop=$_bf_stop; out=$out; rc=$rc" return 0 fi if [ "$_bm_thresh" = "natacpi" ]; then out=$(read_sysf "$_bf_stop") || rc=4 else # no threshold api rc=255 fi # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold: bf_stop=$_bf_stop; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write charge thresholds for a battery # use pre-determined method and sysfiles from global parms # $1: new start threshold -- unused dummy for plugin api compatibility # $2: new stop threshold 80/100/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bat_str, $_bt_cfg_bat, $_bf_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold out of range or non-numeric/ # 4=threshold read error/ # 5=threshold write error/ # 6=threshold write discarded by kernel or firmware # prerequisite: batdrv_init(), batdrv_select_battery() local new_stop=${2:-} local verb=${3:-0} local old_stop # insert defaults [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds local rc if [ -n "$4" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # stop: check for 3 digits max, ensure 80 or 100 if ! is_uint "$new_stop" 3 || ! wordinlist "$new_stop" "80 100"; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": care limit not specified or invalid (must be 80 or 100). Skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": care limit not specified or invalid (must be 80 or 100). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: care limit (%s) not specified or invalid (must be 80 or 100). Aborted.\n" "$new_stop" 1>&2 fi ;; esac return 2 fi # read active stop threshold value if ! old_stop=$(batdrv_read_threshold); then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).read_error: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) echo_message "Error: could not read current care limit. Skipped." ;; 2) printf "Error: could not read current care limit. Aborted.\n" 1>&2 ;; esac return 4 fi # write new threshold if [ "$verb" = "2" ]; then printf "Setting temporary charge threshold for all batteries:\n" fi local rc=0 if [ "$old_stop" != "$new_stop" ]; then # new threshold differs from effective one --> write it if write_sysf "$new_stop" "$_bf_stop"; then if [ "$(read_sysf "$_bf_stop")" != "$new_stop" ]; then # write discarded by kernel or firmware rc=6 fi else # write error rc=5 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).write: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop; rc=$rc" case $verb in 2) if [ $rc -eq 0 ]; then printf " care limit = %d\n" "$new_stop" else printf " care limit = %d (Error: write failed)\n" "$new_stop" 1>&2 fi ;; 1) if [ $rc -gt 0 ]; then echo_message "Error: writing care limit failed." fi ;; esac else echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).no_change: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop" if [ "$verb" = "2" ]; then printf " care limit = %d (no change)\n" "$new_stop" fi fi return $rc } batdrv_chargeonce () { # function not implemented for LG laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.charge_once.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # apply configured battery life extender from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local stop_thresh if batdrv_select_battery "DEF"; then eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "DEF" "$stop_thresh" 1 1 fi return 0 } batdrv_read_force_discharge () { # function not implemented for LG laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge.not_implemented" return 255 } batdrv_write_force_discharge () { # function not implemented for LG laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented for LG laptops echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented for LG laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented for LG laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_bm_thresh, $_natacpi, $_bd_read, $_bf_stop # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" if [ "$_bm_thresh" = "natacpi" ]; then printf "Supported features: charge threshold\n" else printf "Supported features: none available\n" fi printf "Driver usage:\n" # vendor specific kernel api case $_natacpi in 0) printf "* vendor (%s) = active (charge threshold)\n" "$_batdrv_kmod" ;; 32) printf "* vendor (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* vendor (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* vendor (%s) = inactive (laptop not supported)\n" "$_batdrv_kmod" ;; *) printf "* vendor (%s) = unknown status\n" "$_batdrv_kmod" ;; esac if [ "$_bm_thresh" = "natacpi" ]; then local th printf "Parameter value range:\n" printf "* STOP_CHARGE_THRESH_BAT0: 80(on), 100(off) -- battery care limit\n\n" if th=$(batdrv_read_threshold); then printf "%-59s = %d [%%]\n" "$_bf_stop" "$th" else printf "%-59s = %s\n" "$_bf_stop" "(not available)" fi fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi # --- show battery features: thresholds # --- show charge level (SOC) and capacity if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # no recommendations for LG laptops return 0 } ukui-power-manager/3rd/tlp/bat.d/60-macbook0000664000175000017500000005302015167661430017270 0ustar fengfeng#!/bin/sh # 60-macbook - Battery Plugin for Apple Silicon Macbooks w/ applesmc driver # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat # --- Hardware Detection readonly BATDRV_APPLESMC_MD=/sys/class/power_supply/macsmc-battery batdrv_is_applesmc () { # check if vendor specific kernel module is loaded # rc: 0=ok, 1=other hardware [ -d $BATDRV_APPLESMC_MD ] } # --- Plugin API functions batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $_batdrv_kmod # # 1. check for native kernel acpi (Linux 5.4 or higher required) # --> retval $_natacpi: # 0=thresholds/ # 32=disabled/ # 128=no kernel support/ # 254=laptop not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi # # 3. define sysfile basenames for natacpi # start threshold --> retval $_bn_start, # stop threshold --> retval $_bn_stop, # discharge --> retval $_bn_discharge # # 4. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 5. define charge threshold defaults # start threshold --> retval $_bt_def_start, # stop threshold --> retval $_bt_def_stop; _batdrv_plugin="macbook" _batdrv_kmod="macsmc_power" # kernel module for natacpi (Asahi Linux) # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! batdrv_is_applesmc; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_match" return 1 fi fi # presume no features at all _natacpi=128 # shellcheck disable=SC2034 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _bn_start="" _bn_stop="" _bn_dischg="" _batteries="" _bt_def_start=100 _bt_def_stop=100 # iterate batteries and check for native kernel ACPI # note: assume only one battery called "macsmc-battery" local bd bs local done=0 local bat_glob="macsmc-battery" if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then bat_glob='BAT[01]' fi for bd in "$ACPIBATDIR"/$bat_glob; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi # skip natacpi detection for 2nd and subsequent batteries [ $done -eq 1 ] && continue done=1 if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 continue fi if [ -f "$bd/charge_control_start_threshold" ] \ && [ -f "$bd/charge_control_end_threshold" ]; then # threshold sysfiles exist _bn_start="charge_control_start_threshold" _bn_stop="charge_control_end_threshold" _natacpi=254 else # nothing detected _natacpi=254 continue fi if readable_sysf "$bd/$_bn_start" \ && readable_sysf "$bd/$_bn_stop"; then # threshold sysfiles are actually readable _natacpi=0 _bm_thresh="natacpi" if readable_sysf "$bd/charge_behaviour"; then # sysfile for force-discharge exists and is actually readable _bm_dischg="natacpi" _bn_dischg="charge_behaviour" fi fi fi done # quit if no battery detected, there is no point in activating the plugin if [ -z "$_batteries" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_batteries" return 2 fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; thresh=$_bm_thresh; bn_start=$_bn_start; bn_stop=$_bn_stop; dischg=$_bm_dischg; bn_dischg=$_bn_dischg" return 0 } batdrv_select_battery () { # determine battery acpidir and sysfiles # $1: macsmc-battery/DEF # global params: $_batdrv_plugin, $_batteries, $_bn_start, $_bn_stop, $_bn_dischg # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: macsmc-battery; # $_bt_cfg_bat: config suffix (BAT0); # $_bd_read: directory with battery data sysfiles; # $_bf_start: sysfile for start threshold; # $_bf_stop: sysfile for stop threshold; # $_bf_dischg: sysfile for force-discharge; # prerequisite: batdrv_init() # defaults _bat_str="" # no bat _bt_cfg_bat="" _bd_read="" # no directory _bf_start="" _bf_stop="" _bf_dischg="" local bat="$1" # convert battery param to lowercase for backward compatibility # with versions earlier than 1.7, but not in simulation if [ -z "$X_BAT_PLUGIN_SIMULATE" ]; then bat="$(printf '%s' "$bat" | tr "[:upper:]" "[:lower:]")" fi # validate battery param case "$bat" in DEF|def) # 1st battery is default _bat_str="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then _bat_str="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # one battery only -> always use BAT0 config _bt_cfg_bat="BAT0" # determine natacpi sysfiles _bd_read="$ACPIBATDIR/$_bat_str" if [ "$_bm_thresh" = "natacpi" ]; then _bf_start="$ACPIBATDIR/$_bat_str/$_bn_start" _bf_stop="$ACPIBATDIR/$_bat_str/$_bn_stop" fi if [ "$_bm_dischg" = "natacpi" ]; then _bf_dischg="$ACPIBATDIR/$_bat_str/$_bn_dischg" fi echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; cfg=$_bt_cfg_bat; bd_read=$_bd_read; bf_start=$_bf_start; bf_stop=$_bf_stop; bf_dischg=$_bf_dischg" return 0 } batdrv_read_threshold () { # read and print charge threshold # $1: start/stop # $2: 0=api/1=tlp-stat output # global params: $_batdrv_plugin, $_bm_thresh, $_bf_start, $_bf_stop # out: # - api: 0..100/"" on error # - tlp-stat: 0..100/"(not available)" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local bf out="" rc=0 case $1 in start) out="$X_THRESH_SIMULATE_START" ;; stop) out="$X_THRESH_SIMULATE_STOP" ;; esac if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1, $2).simulate: bm_thresh=$_bm_thresh; bf=$bf; out=$out; rc=$rc" return 0 fi if [ "$_bm_thresh" = "natacpi" ]; then # read threshold from sysfile case $1 in start) bf=$_bf_start ;; stop) bf=$_bf_stop ;; esac if ! out=$(read_sysf "$bf"); then # not readable/non-existent if [ "$2" != "1" ]; then out="" else out="(not available)" fi rc=4 fi else # no threshold api if [ "$2" = "1" ]; then out="(not available)" fi rc=255 fi # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else if [ "$2" = "1" ]; then printf "(not available)\n" fi rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1, $2): bm_thresh=$_bm_thresh; bf=$bf; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write both charge thresholds for a battery # use pre-determined method and sysfiles from global parms # notes: # * Apple Silicon hardware with MacOS 13.0 or later firmware provides only two discrete threshold value pairs: # 100/100 or 75/80 # * The kernel driver discards writes to the start threshold; upon reading, it returns a discrete value that # matches the stop threshold # $1: new start threshold -- unused dummy for plugin api compatibility # $2: new stop threshold 80/100/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bm_thresh, $_bat_str, $_bt_cfg_bat, $_bf_start, $_bf_stop, $_bt_def_start, $_bt_def_stop, # rc: 0=ok/ # 1=not configured/ # 2=threshold(s) out of range or non-numeric/ # 3=minimum start stop diff violated/ # 4=threshold read error/ # 5=threshold write error # prerequisite: batdrv_init(), batdrv_select_battery() local new_start=${1:-} local new_stop=${2:-} local verb=${3:-0} local old_stop # insert defaults [ "$new_start" = "DEF" ] && new_start=$_bt_def_start [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds if [ -n "$4" ] && [ -z "$new_start" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # stop: check for 3 digits max, ensure 80 or 100 if ! is_uint "$new_stop" 3 || ! wordinlist "$new_stop" "80 100"; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($2, $3, $4).invalid_stop: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": not specified or invalid (must be 80 or 100). Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": not specified or invalid (must be 80 or 100). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: stop charge threshold (%s) for %s is not specified or invalid (must be 80 or 100). Aborted.\n" "$new_stop" "$_bat_str" 1>&2 fi ;; esac return 2 fi # start threshold value depends on stop threshold (hardware constraint) case "$new_stop" in 80) new_start="75" ;; 100) new_start="100" ;; esac # read active stop threshold value if ! old_stop=$(batdrv_read_threshold stop 0); then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).read_error: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) echo_message "Error: could not read current stop charge threshold for $_bat_str. Battery skipped." ;; 2) printf "Error: could not read current stop charge threshold for %s. Aborted.\n" "$_bat_str" 1>&2 ;; esac return 4 fi # write new stop threshold if [ "$verb" = "2" ]; then printf "Setting temporary charge thresholds for %s:\n" "$_bat_str" fi local rc=0 if [ "$old_stop" != "$new_stop" ]; then # new threshold differs from effective one --> write it write_sysf "$new_stop" "$_bf_stop" || rc=5 echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).stop.write: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop; rc=$rc" case $verb in 2) if [ $rc -eq 0 ]; then printf " stop = %3d\n" "$new_stop" printf " start = %3d (due to hardware constraint)\n" "$new_start" else printf " stop = %3d (Error: write failed)\n" "$new_stop" 1>&2 fi ;; 1) if [ $rc -gt 0 ]; then echo_message "Error: writing stop charge threshold for $_bat_str failed." fi ;; esac else echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).stop.no_change: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop" if [ "$verb" = "2" ]; then printf " stop = %3d (no change)\n" "$new_stop" printf " start = %3d (no change)\n" "$new_start" fi fi echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).complete: bat=$_bat_str; cfg=$_bt_cfg_bat; rc=$rc" return $rc } batdrv_chargeonce () { # function not implemented # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.charge_once.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # apply configured stop thresholds from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # global param: $_batdrv_plugin # prerequisite: batdrv_init() if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then if batdrv_select_battery BAT0; then batdrv_write_thresholds "$START_CHARGE_THRESH_BAT0" "$STOP_CHARGE_THRESH_BAT0" 1 1; rc=$? fi else if batdrv_select_battery macsmc-battery; then batdrv_write_thresholds "$START_CHARGE_THRESH_BAT0" "$STOP_CHARGE_THRESH_BAT0" 1 1; rc=$? fi fi return 0 } batdrv_read_force_discharge () { # read and print force-discharge state # $1: 0=api/1=tlp-stat output # global params: $_batdrv_plugin, $_bm_dischg, $_bat_str, $_bf_dischg # out: # - api: 0=off/1=on/"" on error # - tlp-stat: status text/"(not available)" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local rc=0 out="" if [ "$_bm_dischg" = "natacpi" ]; then # read state from sysfile if out=$(read_sysf "$_bf_dischg"); then if [ "$1" != "1" ]; then if echo "$out" | grep -q "\[force-discharge\]"; then out=1 else out=0 fi fi else # not readable/non-existent if [ "$1" != "1" ]; then out="" else out="(not available)" fi rc=4 fi else # no discharge api if [ "$1" = "1" ]; then out="(not available)" fi rc=255 fi printf "%s" "$out" if [ "$rc" -gt 0 ]; then # log output in the error case only echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge($_bat_str): bm_dischg=$_bm_dischg; bf_dischg=$_bf_dischg; out=$out; rc=$rc" fi return $rc } batdrv_write_force_discharge () { # function not implemented # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented # global param: $_batdrv_plugin # prerequisite: batdrv_init() # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_natacpi, $_bm_thresh, $_bd_read, $_bf_start, $_bf_stop, $_bf_dischg # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" if [ "$_bm_thresh" != "none" ]; then printf "Supported features: charge thresholds\n" else printf "Supported features: none available\n" fi printf "Driver usage:\n" # native kernel ACPI battery API case $_natacpi in 0) printf "* natacpi (%s) = active (charge thresholds)\n" "$_batdrv_kmod" ;; 32) printf "* natacpi (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* natacpi (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* natacpi (%s) = inactive (laptop not supported)\n" "$_batdrv_kmod" ;; *) printf "* natacpi (%s) = unknown status\n" "$_batdrv_kmod" ;; esac if [ "$_bm_thresh" != "none" ]; then printf "Parameter value ranges:\n" printf "* START_CHARGE_THRESH_BAT0: don't care (hardware enforces 75, 100)\n" printf "* STOP_CHARGE_THRESH_BAT0: 80, 100(default)\n" fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi # --- show battery features: thresholds, force_discharge local lf=0 if [ "$_bm_thresh" = "natacpi" ]; then printf "%-69s = %6s [%%]\n" "$_bf_start" "$(batdrv_read_threshold start 1)" printf "%-69s = %6s [%%]\n" "$_bf_stop" "$(batdrv_read_threshold stop 1)" lf=1 fi if [ "$_bm_dischg" = "natacpi" ]; then printf "%-69s = %6s\n" "$_bf_dischg" "$(batdrv_read_force_discharge 1)" lf=1 fi [ $lf -gt 0 ] && printf "\n" # --- show charge level (SOC) and capacity lf=0 if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # no recommendations return 0 } ukui-power-manager/3rd/tlp/bat.d/89-asus0000664000175000017500000004240415167661430016647 0ustar fengfeng#!/bin/sh # 15-asus - Battery Plugin for ASUS laptops w/ asus_wmi driver # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat # --- Hardware Detection readonly BATDRV_ASUS_MD=/sys/module/asus_wmi batdrv_is_asus () { # check if kernel module loaded # rc: 0=ASUS, 1=other hardware [ -d $BATDRV_ASUS_MD ] } # --- Plugin API functions batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $_batdrv_kmod # # 1. check for native kernel acpi (Linux 5.4 or higher required) # --> retval $_natacpi: # 0=thresholds/ # 32=disabled/ # 128=no kernel support/ # 254=laptop not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi # # 3. define sysfile basename for natacpi # stop threshold --> retval $_bn_stop, # # 4. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 5. define charge threshold defaults # stop threshold --> retval $_bt_def_stop; _batdrv_plugin="asus" _batdrv_kmod="asus_wmi" # kernel module for natacpi # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! batdrv_is_asus; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_match" return 1 fi fi # presume no features at all _natacpi=128 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _bn_stop="" _batteries="" _bt_def_stop=100 # iterate batteries and check for native kernel ACPI local bd bs local done=0 for bd in "$ACPIBATDIR"/BAT[01CT]; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi # skip natacpi detection for 2nd and subsequent batteries [ $done -eq 1 ] && continue done=1 if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 elif [ -f "$bd/charge_control_end_threshold" ] && readable_sysf "$bd/charge_control_end_threshold"; then # sysfile for stop threshold exists and is actually readable _natacpi=0 _bm_thresh="natacpi" _bn_stop="charge_control_end_threshold" elif [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then # simulate api _natacpi=0 _bm_thresh="natacpi" _bn_stop="charge_control_end_threshold" else # nothing detected _natacpi=254 fi fi done # quit if no battery detected, there is no point in activating the plugin if [ -z "$_batteries" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_batteries" return 2 fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; thresh=$_bm_thresh; stop=$_bn_stop;" return 0 } batdrv_select_battery () { # determine battery acpidir and sysfile # $1: BAT0/BATC/BATT/BAT1/DEF # global params: $_batdrv_plugin, $_batteries, $_bn_stop # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0/BATC/BATT/BAT1; # $_bt_cfg_bat: config suffix (BAT0/BAT1); # $_bd_read: directory with battery data sysfiles; # $_bf_stop: sysfile for stop threshold; # prerequisite: batdrv_init() # defaults _bat_str="" # no bat _bt_cfg_bat="" _bd_read="" # no directory _bf_stop="" local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]")" # validate battery param case "$bat" in DEF) # 1st battery is default _bat_str="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then _bat_str="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac case "$_bat_str" in BAT0|BATC|BATT) _bt_cfg_bat="BAT0" ;; BAT1) _bt_cfg_bat="BAT1" ;; *) _bt_cfg_bat="BAT0" ;; esac # determine natacpi sysfile _bd_read="$ACPIBATDIR/$_bat_str" if [ "$_bm_thresh" = "natacpi" ]; then _bf_stop="$ACPIBATDIR/$_bat_str/$_bn_stop" fi echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; cfg=$_bt_cfg_bat; bd_read=$_bd_read; bf_stop=$_bf_stop" return 0 } batdrv_read_threshold () { # read and print charge threshold (stop only) # $1: 0=api/1=tlp-stat output # global params: $_batdrv_plugin, $_bm_thresh, $_bf_stop # out: # - api: 0..100/"" on error # - tlp-stat: 0..100/"(not available)" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local out="" rc=0 out="$X_THRESH_SIMULATE_STOP" if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1).simulate: bm_thresh=$_bm_thresh; bf_stop=$_bf_stop; out=$out; rc=$rc" return 0 fi if [ "$_bm_thresh" = "natacpi" ]; then if ! out=$(read_sysf "$_bf_stop"); then # not readable/non-existent if [ "$1" != "1" ]; then out="" else out="(not available)" fi rc=4 fi else # no threshold api if [ "$1" = "1" ]; then out="(not available)" fi rc=255 fi # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else if [ "$1" = "1" ]; then printf "(not available)\n" fi rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1): bm_thresh=$_bm_thresh; bf_stop=$_bf_stop; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write charge thresholds for a battery # use pre-determined method and sysfiles from global parms # $1: new start threshold -- unused dummy for plugin api compatibility # $2: new stop threshold 1..100/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bm_thresh, $_bat_str, $_bt_cfg_bat, $_bf_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold out of range or non-numeric/ # 4=threshold read error/ # 5=threshold write error # prerequisite: batdrv_init(), batdrv_select_battery() local new_stop=${2:-} local verb=${3:-0} # insert defaults [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds if [ -n "$4" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # stop: check for 3 digits max, ensure min 1 / max 100 if ! is_uint "$new_stop" 3 || \ ! is_within_bounds "$new_stop" 1 100; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": not specified, invalid or out of range (1..100). Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": not specified, invalid or out of range (1..100). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: stop charge threshold (%s) for %s is not specified, invalid or out of range (1..100). Aborted.\n" "$new_stop" "$_bat_str" 1>&2 fi ;; esac return 2 fi # give hint if threshold is not 40, 60, 80 or 100(off) if ! wordinlist "$new_stop" "40 60 80 100"; then case $verb in 1) if [ -n "$4" ]; then echo_message "Notice: some ASUS laptops silently ignore charge thresholds other than 40, 60 or 80. Please check if STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\" works as expected." fi ;; 2) if [ -n "$4" ]; then echo_message "Notice: some ASUS laptops silently ignore charge thresholds other than 40, 60 or 80. Please check if STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\" works as expected." else printf "Notice: some ASUS laptops silently ignore charge thresholds other than 40, 60 or 80. Please check if %s works as expected.\n" "$new_stop" fi ;; esac fi # write new threshold if [ "$verb" = "2" ]; then printf "Setting temporary charge threshold for %s:\n" "$_bat_str" fi local rc=0 write_sysf "$new_stop" "$_bf_stop" || rc=5 echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($2, $3, $4).write: bat=$_bat_str; cfg=$_bt_cfg_bat; new=$new_stop; rc=$rc" case $verb in 2) if [ $rc -eq 0 ]; then printf " stop = %3d\n" "$new_stop" else printf " stop = %3d (Error: write failed)\n" "$new_stop" 1>&2 fi ;; 1) if [ $rc -gt 0 ]; then echo_message "Error: writing stop charge threshold for $_bat_str failed." fi ;; esac return $rc } batdrv_chargeonce () { # function not implemented for ASUS laptops echo_debug "bat" "batdrv.${_batdrv_plugin}.charge_once.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # apply configured stop thresholds from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local bat stop_thresh for bat in BAT0 BATC BATT BAT1; do if batdrv_select_battery "$bat"; then eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "DEF" "$stop_thresh" 1 1; rc=$? fi done return 0 } batdrv_read_force_discharge () { # function not implemented for ASUS laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge.not_implemented" return 255 } batdrv_write_force_discharge () { # function not implemented for ASUS laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented for ASUS laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented for ASUS laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented for ASUS laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_bd_read, $_bf_stop # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" if [ "$_bm_thresh" = "natacpi" ]; then printf "Supported features: charge threshold\n" else printf "Supported features: none available\n" fi printf "Driver usage:\n" # native kernel ACPI battery API case $_natacpi in 0) printf "* natacpi (%s) = active (charge threshold)\n" "$_batdrv_kmod" ;; 32) printf "* natacpi (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* natacpi (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* natacpi (%s) = inactive (laptop not supported)\n" "$_batdrv_kmod" ;; *) printf "* natacpi (%s) = unknown status\n" "$_batdrv_kmod" ;; esac if [ "$_bm_thresh" = "natacpi" ]; then printf "Parameter value range:\n" printf "* STOP_CHARGE_THRESH_BAT0/1: 0(off)..100(default)\n" fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi # --- show battery features: thresholds if [ "$_bm_thresh" = "natacpi" ]; then printf "%-59s = %6s [%%]\n" "$_bf_stop" "$(batdrv_read_threshold 1)" printf "\n" fi # --- show charge level (SOC) and capacity lf=0 if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # no recommendations for ASUS laptops return 0 } ukui-power-manager/3rd/tlp/bat.d/05-thinkpad0000664000175000017500000015002615167661430017462 0ustar fengfeng#!/bin/sh # 05-thinkpad - Battery Plugin for ThinkPads using natacpi and/or # tpacpi-bat/acpi-call for thresholds and forced discharge, i.e. X220/T420 and newer. # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat # --- Hardware Detection readonly SMAPIBATDIR=/sys/devices/platform/smapi readonly RE_TPSMAPI_ONLY='^(Edge( 13.*)?|G41|R[56][012][eip]?|R[45]00|SL[45]10|T23|T[346][0123][p]?|T[45][01]0[s]?|W[57][01][01]|X[346][012][s]?( Tablet)?|X1[02]0e|X[23]0[01][s]?( Tablet)?|Z6[01][mpt])$' readonly RE_TPSMAPI_AND_TPACPI='^(X1|X220[s]?( Tablet)?|T[45]20[s]?|W520)$' readonly RE_TP_NONE='^(L[45]20|L512|SL[345]00|X121e)$' readonly MODINFO=modinfo readonly MOD_TPSMAPI="tp_smapi" readonly MOD_TPACPI="acpi_call" supports_tpsmapi_only () { # rc: 0=ThinkPad supports tpsmapi only/1=false # prerequisite: check_thinkpad() printf '%s' "$_tpmodel" | grep -E -q "${RE_TPSMAPI_ONLY}" } supports_tpsmapi_and_tpacpi () { # rc: 0=ThinkPad supports tpsmapi, tpacpi-bat, natacpi/1=false # prerequisite: check_thinkpad() printf '%s' "$_tpmodel" | grep -E -q "${RE_TPSMAPI_AND_TPACPI}" } supports_no_tp_bat_funcs () { # rc: 0=ThinkPad doesn't support battery features/1=false # prerequisite: check_thinkpad() printf '%s' "$_tpmodel" | grep -E -q "${RE_TP_NONE}" } check_thinkpad () { # check for ThinkPad hardware and save model string # rc: 0=ThinkPad, 1=other hardware # retval: $_tpmodel local pv _tpmodel="" if [ -d "$TPACPID" ]; then # kernel module thinkpad_acpi is loaded if [ -z "$X_SIMULATE_MODEL" ]; then # get DMI product_version string and sanitize it pv="$(read_dmi product_version | tr -C -d 'a-zA-Z0-9 ')" else # simulate arbitrary model pv="$X_SIMULATE_MODEL" fi # stock BIOS: check DMI product_version string for occurrence of "ThinkPad" if printf '%s' "$pv" | grep -E -q 'Think[Pp]ad'; then # it's a real ThinkPad --> save model substring _tpmodel=$(printf '%s\n' "$pv" | sed -r 's/^Think[Pp]ad //') elif [ -z "$X_SIMULATE_MODEL" ]; then # Libreboot uses DMI product_name, check it too pv="$(read_dmi product_name | tr -C -d 'a-zA-Z0-9 ')" if printf '%s' "$pv" | grep -E -q 'Think[Pp]ad'; then # it's a librebooted' ThinkPad --> save model substring _tpmodel=$(printf '%s\n' "$pv" | sed -r 's/^Think[Pp]ad //') fi fi else # not a ThinkPad: get DMI product string pv="$(read_dmi product_version)" fi if [ -n "$_tpmodel" ]; then # ThinkPad echo_debug "bat" "check_thinkpad: tpmodel=$_tpmodel" return 0 else # not a ThinkPad echo_debug "bat" "check_thinkpad.not_a_thinkpad: model=$pv" return 1 fi } # --- Plugin API functions batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $_batdrv_kmod # # 1. check for native kernel acpi (Linux 4.19 or higher required) # --> retval $_natacpi: # 0=thresholds and discharge/ # 1=thresholds only/ # 32=disabled/ # 128=no kernel support/ # 254=ThinkPad not supported # # 2. check for acpi-call external kernel module and test with integrated # tpacpi-bat [ThinkPads only] # --> retval $_tpacpi: # 0=thresholds and discharge/ # 1=thresholds only/ # 32=disabled/ # 64=acpi_call module not loaded/ # 127=tpacpi-bat not installed/ # 128=acpi_call module not installed/ # 137=kernel error (oops)/ # 253=tpacpi-bat error/ # 254=ThinkPad not supported/ # 255=superseded by natacpi/ # 256=superseded and kernel module not loaded # # 3. check for tp-smapi external kernel module # --> retval $_tpsmapi: # 1=readonly/ # 32=disabled/ # 64=tp_smapi module not loaded/ # 128=tp_smapi module not installed # # 4. determine best method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi/tpacpi/tpsmapi # # 5. determine sysfile basenames for natacpi # start threshold --> retval $_bn_start, # stop threshold --> retval $_bn_stop, # force discharge --> retval $_bn_dischg; # # 6. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 7. define charge threshold defaults # start threshold --> retval $_bt_def_start, # stop threshold --> retval $_bt_def_stop; _batdrv_plugin="thinkpad" _batdrv_kmod="thinkpad_acpi" # kernel module for natacpi if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if ThinkPad if ! check_thinkpad; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.not_a_thinkpad" return 1 elif supports_no_tp_bat_funcs; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.unsupported_model" return 1 fi fi # presume no features at all _natacpi=128 _tpacpi=255 _tpsmapi=254 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _bn_start="" _bn_stop="" _bn_dischg="" _batteries="" _bt_def_start=96 _bt_def_stop=100 # --- 1. iterate batteries and check for native kernel ACPI local bd bs local done=0 for bd in "$ACPIBATDIR"/BAT[01]; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi # skip natacpi detection for 2nd and subsequent batteries [ $done -eq 1 ] && continue done=1 if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 continue fi if [ -f "$bd/charge_control_start_threshold" ] \ && [ -f "$bd/charge_control_end_threshold" ]; then # sysfiles for thresholds exist (kernel 5.9 and newer) _bn_start="charge_control_start_threshold" _bn_stop="charge_control_end_threshold" _natacpi=254 elif [ -f "$bd/charge_start_threshold" ] \ && [ -f "$bd/charge_stop_threshold" ]; then # sysfiles for thresholds exist (kernel 4.17 and newer) _bn_start="charge_start_threshold" _bn_stop="charge_stop_threshold" _natacpi=254 else # nothing detected _natacpi=128 continue fi if readable_sysf "$bd/$_bn_start" \ && readable_sysf "$bd/$_bn_stop"; then # start/stop thresholds are actually readable _natacpi=1 _bm_thresh="natacpi" if [ -f "$bd/charge_behaviour" ]; then if grep -q "force-discharge" "$bd/charge_behaviour"; then # sysfile exists and flags the force-discharge capability _natacpi=0 _bm_dischg="natacpi" fi _bn_dischg="charge_behaviour" fi fi fi done # quit if no battery detected, there is no point in activating the plugin if [ -z "$_batteries" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_batteries" return 2 fi # consider legacy ThinkPads with coreboot/natacpi if supports_tpsmapi_only && [ $_natacpi -ge 32 ]; then # no natacpi --> do not probe acpi_call/tpacpi-bat but quit i.e. try 10-thinkpad-legacy next echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_natacpi: batteries=$_batteries; natacpi=$_natacpi; tpacpi=$_tpacpi; tpsmapi=$_tpsmapi" return 1 fi # --- 2. probe acpi_call external kernel module and test with integrated tpacpi-bat # do not probe if coreboot/natacpi without force-discharge capability was detected before if [ $_natacpi -gt 0 ] && [ -z "$_bn_dischg" ]; then load_modules $MOD_TPACPI if [ ! -e /proc/acpi/call ]; then # call API not present if $MODINFO $MOD_TPACPI > /dev/null 2>&1; then # module installed but not loaded _tpacpi=64 else # module neither installed nor builtin _tpacpi=128 fi else # call API present --> try tpacpi-bat if $TPACPIBAT -g ST 1 > /dev/null 2>&1; then # thresholds capable _tpacpi=1 if $TPACPIBAT -g FD 1 > /dev/null 2>&1; then # force_discharge capable _tpacpi=0 fi else # tpacpi-bat failed case $? in 255) # acpi call non-existent (AE_NOT_FOUND) _tpacpi=254 ;; 137) # kernel error (oops) _tpacpi=137 ;; * ) # tpacpi-bat error _tpacpi=253 ;; esac fi if [ $_tpacpi -le 1 ]; then # tpacpi capable if [ "$TPACPI_ENABLE" = "0" ]; then # disabled by configuration _tpacpi=32 else # not disabled case $_natacpi in 1) # use for discharge only [ $_tpacpi -eq 0 ] && _bm_dischg="tpacpi" ;; *) # use for thresholds and discharge _bm_thresh="tpacpi" [ $_tpacpi -eq 0 ] && _bm_dischg="tpacpi" ;; esac fi fi fi elif [ ! -e /proc/acpi/call ]; then # superseded and kernel module not loaded _tpacpi=256 fi # --- 3. probe tp-smapi external kernel module (relevant models only) if supports_tpsmapi_and_tpacpi; then load_modules $MOD_TPSMAPI if [ -d $SMAPIBATDIR ]; then # module loaded --> tp-smapi available if [ "$TPSMAPI_ENABLE" = "0" ]; then # tpsmapi disabled by configuration _tpsmapi=32 else # reading battery data via tpsmapi is preferred over natacpi # because it provides cycle count and more _tpsmapi=1 _bm_read="tpsmapi" fi elif $MODINFO $MOD_TPSMAPI > /dev/null 2>&1; then # module installed but not loaded _tpsmapi=64 else # module neither installed nor builtin _tpsmapi=128 fi fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; tpacpi=$_tpacpi; tpsmapi=$_tpsmapi" echo_debug "bat" "batdrv_init.${_batdrv_plugin}: read=$_bm_read; thresh=$_bm_thresh; bn_start=$_bn_start; bn_stop=$_bn_stop; dischg=$_bm_dischg; bn_dischg=$_bn_dischg" return 0 } batdrv_select_battery () { # determine battery sysfiles and tpacpi-bat index # $1: BAT0/BAT1/DEF # global params: $_batdrv_plugin, $_batteries, $_bm_read, $_bm_dischg, $_bn_start, $_bn_stop, $_bn_dischg # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0/BAT1; # $_bt_cfg_bat: config suffix = BAT0/BAT1; # $_bat_idx: 1/2; # $_bd_read: directory with battery data sysfiles; # $_bf_start: sysfile for start threshold; # $_bf_stop: sysfile for stop threshold; # $_bf_dischg: sysfile for force discharge # prerequisite: batdrv_init() # defaults _bat_idx=0 # no index _bat_str="" # no bat _bd_read="" # no directories _bf_start="" _bf_stop="" _bf_dischg="" _bt_cfg_bat="" local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]")" # validate battery param local bs case "$bat" in DEF) # 1st battery is default bs="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then bs="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # determine battery name and index for tpacpi and main/aux distinction case $bs in BAT0) _bat_str="$bs" # BAT0 is always assumed main battery _bat_idx=1 ;; BAT1) _bat_str="$bs" if [ "$_tpacpi" -le 1 ]; then # tpacpi: try to read start threshold for index 2 if $TPACPIBAT -g ST 2 2> /dev/null 1>&2 ; then _bat_idx=2 # BAT1 is aux else _bat_idx=1 # BAT1 is main fi else # without tpacpi: BAT1 is aux _bat_idx=2 fi ;; esac # config suffix equals battery name _bt_cfg_bat="$_bat_str" # determine natacpi sysfiles if [ "$_bm_thresh" = "natacpi" ]; then _bf_start="$ACPIBATDIR/$bs/$_bn_start" _bf_stop="$ACPIBATDIR/$bs/$_bn_stop" fi if [ "$_bm_dischg" = "natacpi" ]; then _bf_dischg="$ACPIBATDIR/$bs/$_bn_dischg" fi case "$_bm_read" in natacpi) _bd_read="$ACPIBATDIR/$bs" ;; tpsmapi) _bd_read="$SMAPIBATDIR/$bs" ;; esac echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; cfg=$_bt_cfg_bat; bat_idx=$_bat_idx; bd_read=$_bd_read; bf_start=$_bf_start; bf_stop=$_bf_stop; bf_dischg=$_bf_dischg" return 0 } batdrv_read_threshold () { # read and print charge threshold # $1: start/stop # $2: 0=api/1=tlp-stat output # global params: $_batdrv_plugin, $_bm_thresh, $_bf_start, $_bf_stop, $_bat_idx # out: # - api: 0..100/"" on error # - tlp-stat: 0..100/"(not available)" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local bf out="" rc=0 case $1 in start) out="$X_THRESH_SIMULATE_START" ;; stop) out="$X_THRESH_SIMULATE_STOP" ;; esac if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1, $2).simulate: bm_thresh=$_bm_thresh; bf=$bf; bat_idx=$_bat_idx; out=$out; rc=$rc" return 0 fi case $_bm_thresh in natacpi) # read threshold from sysfile case $1 in start) bf=$_bf_start ;; stop) bf=$_bf_stop ;; esac if ! out=$(read_sysf "$bf"); then # not readable/non-existent if [ "$2" != "1" ]; then out="" else out="(not available)" fi rc=4 fi # workaround: read threshold sysfile a second time to mitigate # the annoying firmware issue on ThinkPad A/E/L/S/X series # (refer to issue #369 and FAQ) if ! out=$(read_sysf "$bf"); then # not readable/non-existent if [ "$2" != "1" ]; then out="" else out="(not available)" fi rc=4 fi ;; tpacpi) case $1 in start) out=$($TPACPIBAT -g ST "$_bat_idx" 2> /dev/null | cut -f1 -d' ') # workaround: read threshold a second time (see above) out=$($TPACPIBAT -g ST "$_bat_idx" 2> /dev/null | cut -f1 -d' ') ;; stop) out=$($TPACPIBAT -g SP "$_bat_idx" 2> /dev/null | cut -f1 -d' ') # workaround: read threshold a second time (see above) out=$($TPACPIBAT -g SP "$_bat_idx" 2> /dev/null | cut -f1 -d' ') ;; esac # shellcheck disable=SC2181 if [ $? -eq 0 ] && is_uint "$out"; then if [ "$out" -ge 128 ]; then # remove offset of 128 for Edge S430 et al. out=$((out - 128)) fi if [ "$1" = "stop" ] && [ "$out" -eq 0 ]; then # stop: 0 (hardware default) means 100 out=100 fi else if [ "$2" != "1" ]; then out="" else out="(not available)" fi rc=4 fi ;; *) # no threshold api rc=255 ;; esac # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else if [ "$2" = "1" ]; then printf "(not available)\n" fi rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1, $2): bm_thresh=$_bm_thresh; bf=$bf; bat_idx=$_bat_idx; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write both charge thresholds for a battery # use pre-determined method and sysfiles from global parms # $1: new start threshold 0(disabled)..99/DEF(default) # $2: new stop threshold 1..100/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bm_thresh, $_bat_str, $_bat_idx, $_bt_cfg_bat, $_bf_start, $_bf_stop, $_bt_def_start, $_bt_def_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold(s) out of range or non-numeric/ # 3=minimum start stop diff violated/ # 4=threshold read error/ # 5=threshold write error # prerequisite: batdrv_init(), batdrv_select_battery() local new_start=${1:-} local new_stop=${2:-} local verb=${3:-0} local old_start old_stop # insert defaults [ "$new_start" = "DEF" ] && new_start=$_bt_def_start [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds local rc if [ -n "$4" ] && [ -z "$new_start" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # start: check for 3 digits max, ensure min 0 / max 99 if ! is_uint "$new_start" 3 || \ ! is_within_bounds "$new_start" 0 99; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_start: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at START_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_start}\": not specified, invalid or out of range (0..99). Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at START_CHARGE_THRESH_%s=\"%s\": not specified, invalid or out of range (0..99). Aborted.\n" "$_bt_cfg_bat" "$new_start" 1>&2 else printf "Error: start charge threshold (%s) for %s is not specified, invalid or out of range (0..99). Aborted.\n" "$new_start" "$_bat_str" 1>&2 fi ;; esac return 2 fi # stop: check for 3 digits max, ensure min 1 / max 100 if ! is_uint "$new_stop" 3 || \ ! is_within_bounds "$new_stop" 1 100; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": not specified, invalid or out of range (1..100). Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": not specified, invalid or out of range (1..100). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: stop charge threshold (%s) for %s is not specified, invalid or out of range (1..100). Aborted.\n" "$new_stop" "$_bat_str" 1>&2 fi ;; esac return 2 fi # check if start < stop if [ "$new_start" -ge "$new_stop" ]; then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_diff: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration: START_CHARGE_THRESH_${_bt_cfg_bat} >= STOP_CHARGE_THRESH_${_bt_cfg_bat}. Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration: START_CHARGE_THRESH_%s >= STOP_CHARGE_THRESH_%s. Aborted.\n" "$_bt_cfg_bat" "$_bt_cfg_bat" 1>&2 else printf "Error: start threshold >= stop threshold for %s. Aborted.\n" "$_bat_str" 1>&2 fi ;; esac return 3 fi # read active threshold values if ! old_start=$(batdrv_read_threshold start 0) || \ ! old_stop=$(batdrv_read_threshold stop 0); then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).read_error: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) echo_message "Warning: could not read current charge threshold(s) for $_bat_str. Battery skipped." ;; 2) printf "Error: could not read current charge threshold(s) for %s. Aborted.\n" "$_bat_str" 1>&2 ;; esac return 4 fi if [ "$old_start" -ge "$old_stop" ]; then # invalid threshold reading, happens on ThinkPad E/L series old_start="none" old_stop="none" fi # determine write sequence because driver's intrinsic boundary conditions # must be met in all write stages: # - natacpi: start < stop (write fails if not met) # - tpacpi: nothing (maybe BIOS/ECP enforces something) local rc=0 steprc tseq if [ "$old_stop" != "none" ] && [ "$new_start" -ge "$old_stop" ]; then tseq="stop start" else tseq="start stop" fi # write new thresholds in determined sequence if [ "$verb" = "2" ]; then printf "Setting temporary charge thresholds for %s:\n" "$_bat_str" fi for step in $tseq; do local old_thresh new_thresh steprc case $step in start) old_thresh=$old_start new_thresh=$new_start ;; stop) old_thresh=$old_stop new_thresh=$new_stop ;; esac if [ "$old_thresh" != "$new_thresh" ]; then # new threshold differs from effective one --> write it case $_bm_thresh in natacpi) case $step in start) write_sysf "$new_thresh" "$_bf_start" ;; stop) write_sysf "$new_thresh" "$_bf_stop" ;; esac steprc=$?; [ $steprc -ne 0 ] && [ $rc -eq 0 ] && rc=5 ;; tpacpi) case $step in start) $TPACPIBAT -s ST "$_bat_idx" "$new_thresh" > /dev/null 2>&1 ;; stop) if [ "$new_thresh" -eq 100 ]; then # tpacpi-bat won't accept 100 $TPACPIBAT -s SP "$_bat_idx" 0 > /dev/null 2>&1 else $TPACPIBAT -s SP "$_bat_idx" "$new_thresh" > /dev/null 2>&1 fi ;; esac steprc=$?; [ $steprc -ne 0 ] && rc=5 ;; *) # no threshold api steprc=255 rc=5 ;; esac echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).$step.write: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_thresh; new=$new_thresh; steprc=$steprc" case $verb in 2) if [ $steprc -eq 0 ]; then if [ "$step" = "start" ] && [ "$new_thresh" -eq 0 ]; then printf " %-5s = %3d (disabled)\n" "$step" "$new_thresh" else printf " %-5s = %3d\n" "$step" "$new_thresh" fi else printf " %-5s = %3d (Error: write failed)\n" "$step" "$new_thresh" 1>&2 fi ;; 1) if [ $steprc -gt 0 ]; then echo_message "Error: writing $step charge threshold for $_bat_str failed." fi ;; esac else echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).$step.no_change: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_thresh; new=$new_thresh" if [ "$verb" = "2" ]; then printf " %-5s = %3d (no change)\n" "$step" "$new_thresh" fi fi done # for step echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).complete: bat=$_bat_str; cfg=$_bt_cfg_bat; rc=$rc" return $rc } batdrv_chargeonce () { # charge battery to stop threshold once # use pre-determined method and sysfiles from global parms # global params: $_batdrv_plugin, $_bm_thresh, $_bat_str, $_bat_idx, $_bf_start, $_bf_stop # rc: 0=ok/ # 2=charge level read error # 3=charge level too high/ # 4=threshold read error/ # 5=threshold write error/ # prerequisite: batdrv_init(), batdrv_select_battery() local ccharge cur_stop efull enow temp_start local rc=0 if ! cur_stop=$(batdrv_read_threshold stop 0); then printf "Error: reading stop charge threshold for %s failed. Aborted.\n" "$_bat_str" 1>&2 echo_debug "bat" "batdrv.${_batdrv_plugin}.chargeonce($_bat_str).thresh_unknown: stop=$cur_stop; rc=4" return 4 fi # get current charge level (in %) case $_bm_read in natacpi) # use ACPI sysfiles if [ -f "$_bd_read/energy_full" ]; then efull=$(read_sysval "$_bd_read/energy_full") enow=$(read_sysval "$_bd_read/energy_now") fi if is_uint "$enow" && is_uint "$efull" && [ "$efull" -ne 0 ]; then # calculate charge level rounded to integer ccharge=$(perl -e 'printf("%.0f\n", 100.0 * '"$enow"' / '"$efull"')') else ccharge=-1 fi ;; tpsmapi) # use tp-smapi sysfile ccharge=$(read_sysval "$_bd_read/remaining_percent") || ccharge=-1 ;; esac if [ "$ccharge" -eq -1 ]; then printf "Error: cannot determine charge level for %s.\n" "$_bat_str" 1>&2 echo_debug "bat" "batdrv.${_batdrv_plugin}.chargeonce($_bat_str).charge_level_unknown: enow=$enow; efull=$efull; rc=2" return 2 fi temp_start=$(( cur_stop - 1 )) if [ "$ccharge" -gt "$temp_start" ]; then printf "Error: the %s charge level is %s%%. " "$_bat_str" "$ccharge" 1>&2 printf "For this command to work, it must not exceed %s%% (stop threshold - 1).\n" "$temp_start" 1>&2 echo_debug "bat" "batdrv.${_batdrv_plugin}.chargeonce($_bat_str).charge_level_too_high: soc=$ccharge; stop=$cur_stop; rc=3" return 3 fi printf "Setting temporary charge threshold for %s:\n" "$_bat_str" case $_bm_thresh in natacpi) write_sysf "$temp_start" "$_bf_start" || rc=5 ;; tpacpi) $TPACPIBAT -s ST "$_bat_idx" "$temp_start" > /dev/null 2>&1 || rc=5 ;; esac if [ $rc -eq 0 ]; then printf " start = %3d\n" "$temp_start" else printf " start = %3d (Error: write failed)\n" "$temp_start" 1>&2 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.chargeonce($_bat_str): soc=$ccharge; start=$temp_start; stop=$cur_stop; rc=$rc" return $rc } batdrv_apply_configured_thresholds () { # apply configured stop thresholds from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local bat start_thresh stop_thresh for bat in BAT0 BAT1; do if batdrv_select_battery "$bat"; then eval start_thresh="\$START_CHARGE_THRESH_${_bt_cfg_bat}" eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "$start_thresh" "$stop_thresh" 1 1 fi done return 0 } batdrv_read_force_discharge () { # read and print force-discharge state # $1: 0=api/1=tlp-stat output # global params: $_batdrv_plugin, $_bm_dischg, $_bat_str, $_bf_dischg, $_bat_idx # out: # - api: 0=off/1=on/"" on error # - tlp-stat: status text/"(not available)" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local rc=0 out="" case $_bm_dischg in natacpi) # read state from sysfile if out=$(read_sysf "$_bf_dischg"); then if [ "$1" != "1" ]; then if echo "$out" | grep -q "\[force-discharge\]"; then out=1 else out=0 fi fi else # not readable/non-existent if [ "$1" != "1" ]; then out="" else out="(not available)" fi rc=4 fi ;; tpacpi) # read via tpacpi-bat case "$($TPACPIBAT -g FD "$_bat_idx" 2> /dev/null)" in yes) out=1 ;; no) out=0 ;; *) if [ "$1" != "1" ]; then out="" else out="(not available)" fi rc=4 ;; esac ;; *) # no discharge api if [ "$1" = "1" ]; then out="(not available)" fi rc=255 ;; esac printf "%s" "$out" if [ "$rc" -gt 0 ]; then # log output in the error case only echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge($_bat_str): bm_dischg=$_bm_dischg; bf_dischg=$_bf_dischg; bat_idx=$_bat_idx; out=$out; rc=$rc" fi return $rc } batdrv_write_force_discharge () { # write force discharge state # $1: 0=off/1=on # global params: $_batdrv_plugin, $_bat_str, $_bat_idx, $_bm_dischg, $_bf_dischg # rc: 0=done/5=write error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local rc=0 case $_bm_dischg in natacpi) # write force_discharge case "$1" in 0) write_sysf "auto" "$_bf_dischg" || rc=5 ;; 1) write_sysf "force-discharge" "$_bf_dischg" || rc=5 ;; esac ;; # natacpi tpacpi) # use tpacpi-bat $TPACPIBAT -s FD "$_bat_idx" "$1" > /dev/null 2>&1 || rc=5 ;; # tpcpaci *) # no discharge api rc=255 ;; esac echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge($_bat_str, $1): bm_dischg=$_bm_dischg; bf_dischg=$_bf_dischg; bat_idx=$_bat_idx; rc=$rc" return $rc } batdrv_cancel_force_discharge () { # trap: called from batdrv_discharge # global params: $_batdrv_plugin, $_bat_str # prerequisite: batdrv_discharge() batdrv_write_force_discharge 0 unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.cancelled($_bat_str)" printf " Cancelled.\n" do_exit 0 } batdrv_force_discharge_active () { # check if battery is in 'force_discharge' state # global params: $_batdrv_plugin, $_bat_str, $_bm_read, $_bd_read # rc: 0=discharging/1=not discharging/2=AC detached/255=no api # retval: $_bat_soc, $_bat_en, $_bat_ef # prerequisite: batdrv_init(), batdrv_select_battery() local bsys rc=0 st="" _bat_soc="" _bat_en=0 _bat_ef=0 if [ "$(batdrv_read_force_discharge 0)" = "0" ]; then # force_discharge is off --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active($_bat_str): rc=1" return 1 fi if ! get_sys_power_supply; then # AC detached --> cancel discharge rc=2 else # force_discharge is still on, but quirky firmware (e.g. ThinkPad E-series) # may keep force_discharge on --> check battery status too case $_bm_read in natacpi) st=$(read_sysf "$_bd_read/status") # determine soc for log entry _bat_en=$(read_sysval "$_bd_read/energy_now") _bat_ef=$(read_sysval "$_bd_read/energy_full") if [ "$_bat_ef" != "0" ]; then _bat_soc=$(perl -e 'printf ("%d", 100.0 * '"$_bat_en"' / '"$_bat_ef"' );') fi ;; tpsmapi) st=$(read_sysf "$_bd_read/state") # determine soc for log entry _bat_soc=$(read_sysf "$_bd_read/remaining_percent") ;; *) # no read api bsys="" rc=255 ;; esac # evaluate battery state case "$st" in [Dd]ischarging) rc=0 ;; *) rc=1 ;; esac fi echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active($_bat_str): bm_read=$_bm_read; bf=$bsys; st=$st; soc=$_bat_soc; rc=$rc" return $rc } batdrv_discharge () { # discharge battery # global params: $_batdrv_plugin, $_bm_dischg, $_bat_str, $_bat_idx, $_bd_read, $_bf_dischg, $_bat_en, $_bat_soc # rc: 0=done/1=malfunction/2=not emptied/3=ac removed/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local en ef pn rc rp wt # start discharge if ! batdrv_write_force_discharge 1; then echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.force_discharge_malfunction($_bat_str)" echo "Error: discharge $_bat_str malfunction -- check your hardware (battery, charger)." 1>&2 return 1 fi trap batdrv_cancel_force_discharge INT # enable ^C hook rc=0; rp=0 # wait for start == while status not "discharging" -- 15.0 sec timeout printf "Initiating discharge of battery %s " "$_bat_str" wt=15 while ! batdrv_force_discharge_active && [ $wt -gt 0 ] ; do sleep 1 printf "." wt=$((wt - 1)) done printf "\n" if batdrv_force_discharge_active; then # discharge initiated sucessfully --> wait for completion == while status "discharging" echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.running($_bat_str)" while batdrv_force_discharge_active; do clear printf "Currently discharging battery %s:\n" "$_bat_str" # show current battery state case $_bm_read in natacpi|tpacpi) # use ACPI sysfiles perl -e 'printf ("voltage = %6d [mV]\n", '"$(read_sysval "$_bd_read/voltage_now")"' / 1000.0);' perl -e 'printf ("remaining capacity = %6d [mWh]\n", '"$_bat_en"' / 1000.0);' if [ -n "$_bat_soc" ]; then perl -e 'printf ("remaining percent = %6d [%%]\n", '"$_bat_soc"' );' else printf "remaining percent = not available [%%]\n" rp=0 fi pn=$(read_sysval "$_bd_read/power_now") if [ "$pn" != "0" ]; then perl -e 'printf ("remaining time = %6d [min]\n", 60.0 * '"$_bat_en"' / '"$pn"');' perl -e 'printf ("power = %6d [mW]\n", '"$pn"' / 1000.0);' else printf "remaining time = not discharging [min]\n" fi printf "state = %s\n" "$(read_sysf "$_bd_read/status")" ;; # natacpi, tpsmapi tpsmapi) # use tp-smapi sysfiles printf "voltage = %6s [mV]\n" "$(read_sysf "$_bd_read/voltage")" printf "remaining capacity = %6s [mWh]\n" "$(read_sysf "$_bd_read/remaining_capacity")" printf "remaining percent = %6s [%%]\n" "$_bat_soc" printf "remaining time = %6s [min]\n" "$(read_sysf "$_bd_read/remaining_running_time_now")" printf "power = %6s [mW]\n" "$(read_sysf "$_bd_read/power_avg")" printf "state = %s\n" "$(read_sysf "$_bd_read/state")" ;; # tpsmapi esac printf "force-discharge = %s\n" "$(batdrv_read_force_discharge 0)" echo "Press Ctrl+C to cancel." sleep 5 done unlock_tlp tlp_discharge # read charge level one last time case $_bm_read in natacpi|tpacpi) # use ACPI sysfiles en=$(read_sysval "$_bd_read/energy_now") ef=$(read_sysval "$_bd_read/energy_full") if [ "$ef" != "0" ]; then rp=$(perl -e 'printf ("%d", 100.0 * '"$en"' / '"$ef"' );') else rp=0 fi ;; # natacpi, tpsmapi tpsmapi) # use tp-smapi sysfiles rp=$(read_sysf "$_bd_read/remaining_percent") ;; esac if [ "$rp" -gt 0 ]; then # SOC > 0% = battery not emptied --> determine cause get_sys_power_supply # shellcheck disable=SC2154 if [ "$_syspwr" -eq 1 ]; then # system on battery --> AC power removed echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.ac_removed($_bat_str)" echo "Warning: battery $_bat_str was not discharged completely -- AC/charger removed." 1>&2 rc=3 elif [ "$rp" -gt 1 ]; then # system on AC, SOC > 1% --> discharging terminated by unknown reason echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_emptied($_bat_str)" echo "Error: battery $_bat_str was not discharged completely i.e. terminated by the firmware -- check your hardware (battery, charger)." 1>&2 rc=2 fi fi else # discharge malfunction --> cancel discharge and abort batdrv_write_force_discharge 0 echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.malfunction($_bat_str)" echo "Error: discharge $_bat_str malfunction -- check your hardware (battery, charger)." 1>&2 rc=1 fi trap - INT # remove ^C hook # ThinkPad E-series firmware may keep force_discharge active --> cancel it [ "$(batdrv_read_force_discharge 0)" = "1" ] && batdrv_write_force_discharge 0 if [ $rc -eq 0 ]; then echo echo "Done: battery $_bat_str was completely discharged." echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.complete($_bat_str)" fi return $rc } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_natacpi, $_tpacpi, $_tpsmapi, # $_bm_thresh, $_bm_dischg, $_bd_read, $_bf_start, $_bf_stop, $_bf_dischg # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" local fs="" [ "$_bm_thresh" != "none" ] && fs="charge thresholds" if [ "$_bm_dischg" != "none" ]; then [ -n "$fs" ] && fs="${fs}, " fs="${fs}recalibration" fi [ -n "$fs" ] || fs="none available" printf "Supported features: %s\n" "$fs" printf "Driver usage:\n" # native kernel ACPI battery API case $_natacpi in 0|1) printf "* natacpi (%s) = active " "$_batdrv_kmod"; print_methods_per_driver "natacpi" ;; 32) printf "* natacpi (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* natacpi (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* natacpi (%s) = inactive (ThinkPad not supported)\n" "$_batdrv_kmod" ;; *) printf "* natacpi (%s) = unknown status\n" "$_batdrv_kmod" ;; esac # ThinkPad-specific battery APIs case $_tpacpi in 0) printf "* tpacpi-bat (acpi_call) = active "; print_methods_per_driver "tpacpi" ;; 1) printf "* tpacpi-bat (acpi_call) = inactive (none)\n" ;; 32) printf "* tpacpi-bat (acpi_call) = inactive (disabled by configuration)\n" ;; 64) printf "* tpacpi-bat (acpi_call) = inactive (kernel module 'acpi_call' load error)\n" ;; 127) printf "* tpacpi-bat (acpi_call) = inactive (program 'tpacpi-bat' not installed)\n" ;; 128) printf "* tpacpi-bat (acpi_call) = inactive (kernel module 'acpi_call' not installed)\n" ;; 137) printf "* tpacpi-bat (acpi_call) = inactive (kernel error)\n" ;; 253) printf "* tpacpi-bat (acpi_call) = inactive (tpacpi-bat error)\n" ;; 254) printf "* tpacpi-bat (acpi_call) = inactive (ThinkPad not supported)\n" ;; 255) printf "* tpacpi-bat (acpi_call) = inactive (superseded by natacpi)\n" ;; 256) ;; # superseded and kernel module not loaded--> be quiet *) printf "* tpacpi-bat = unknown status" ;; esac case $_tpsmapi in 1) printf "* tp-smapi (tp_smapi) = readonly "; print_methods_per_driver "tpsmapi" ;; 32) printf "* tp-smapi (tp_smapi) = inactive (disabled by configuration)\n" ;; 64) printf "* tp-smapi (tp_smapi) = inactive (kernel module 'tp_smapi' load error)\n" ;; 128) printf "* tp-smapi (tp_smapi) = inactive (kernel module 'tp_smapi' not installed)\n" ;; esac if [ "$_bm_thresh" != "none" ]; then printf "Parameter value ranges:\n" printf "* START_CHARGE_THRESH_BAT0/1: 0(off)..96(default)..99\n" printf "* STOP_CHARGE_THRESH_BAT0/1: 1..100(default)\n" fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 local coreboot=0 for bat in $_batteries; do # iterate detected batteries batdrv_select_battery "$bat" case $_bat_idx in 1) printf "+++ ThinkPad Battery Status: %s (Main / Internal)\n" "$bat" ;; 2) printf "+++ ThinkPad Battery Status: %s (Ultrabay / Slice / Replaceable)\n" "$bat" ;; 0) printf "+++ ThinkPad Battery Status: %s\n" "$bat" ;; esac # --- show basic data case $_bm_read in natacpi) # use ACPI data printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then # workaround: coreboot (Skulls) provides ACPI mW(h) values incorrectly: # - using sysfiles for mA(h) # - one decimal place too little # refer to https://github.com/linrunner/TLP/issues/657 coreboot=1 printparm "%-59s = ##%6d## [mWh] *" "$_bd_read/charge_full_design" "" 00 printparm "%-59s = ##%6d## [mWh] *" "$_bd_read/charge_full" "" 00 printparm "%-59s = ##%6d## [mWh] *" "$_bd_read/charge_now" "" 00 printparm "%-59s = ##%6d## [mW] *" "$_bd_read/current_now" "" 00 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi ;; # natacpi tpsmapi) # ThinkPad with active tp-smapi printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model" printparm "%-59s = ##%s##" "$_bd_read/manufacture_date" printparm "%-59s = ##%s##" "$_bd_read/first_use_date" printparm "%-59s = ##%6d##" "$_bd_read/cycle_count" if [ -f "$_bd_read/temperature" ]; then # shellcheck disable=SC2046 perl -e 'printf ("%-59s = %6d [°C]\n", "'"$_bd_read/temperature"'", '$(read_sysval "$_bd_read/temperature")' / 1000.0);' fi printparm "%-59s = ##%6d## [mWh]" "$_bd_read/design_capacity" printparm "%-59s = ##%6d## [mWh]" "$_bd_read/last_full_capacity" printparm "%-59s = ##%6d## [mWh]" "$_bd_read/remaining_capacity" printparm "%-59s = ##%6d## [%%]" "$_bd_read/remaining_percent" printparm "%-59s = ##%6s## [min]" "$_bd_read/remaining_running_time_now" printparm "%-59s = ##%6s## [min]" "$_bd_read/remaining_charging_time" printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_avg" print_batstate "$_bd_read/state" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/design_voltage" printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage" printparm "%-59s = ##%6s## [mV]" "$_bd_read/group0_voltage" printparm "%-59s = ##%6s## [mV]" "$_bd_read/group1_voltage" printparm "%-59s = ##%6s## [mV]" "$_bd_read/group2_voltage" printparm "%-59s = ##%6s## [mV]" "$_bd_read/group3_voltage" printf "\n" fi # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/design_capacity") ef=$(read_sysval "$_bd_read/last_full_capacity") en=$(read_sysval "$_bd_read/remaining_capacity") efsum=$((efsum + ef)) ensum=$((ensum + en)) ;; # tp-smapi esac # $_bm_read # --- show battery features: thresholds, force_discharge local lf=0 case $_bm_thresh in natacpi) printf "%-59s = %6s [%%]\n" "$_bf_start" "$(batdrv_read_threshold start 1)" printf "%-59s = %6s [%%]\n" "$_bf_stop" "$(batdrv_read_threshold stop 1)" lf=1 ;; tpacpi) printf "%-59s = %6s [%%]\n" "tpacpi-bat.${_bat_str}.startThreshold" "$(batdrv_read_threshold start 1)" printf "%-59s = %6s [%%]\n" "tpacpi-bat.${_bat_str}.stopThreshold" "$(batdrv_read_threshold stop 1)" lf=1 ;; esac case $_bm_dischg in natacpi) printf "%-59s = %6s\n" "$_bf_dischg" "$(batdrv_read_force_discharge 1)" lf=1 ;; tpacpi) printf "%-59s = %6s\n" "tpacpi-bat.${_bat_str}.forceDischarge" "$(batdrv_read_force_discharge 1)" lf=1 ;; none) printparm "%-59s = ##%s##" "$_bd_read/$_bn_dischg" lf=1 ;; esac [ $lf -gt 0 ] && printf "\n" # --- show charge level (SOC) and capacity lf=0 if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi if [ "$coreboot" = "1" ]; then printf "*) Converted coreboot charge readings may differ.\n\n" fi return 0 } batdrv_recommendations () { # output ThinkPad specific recommendations # prerequisite: batdrv_init() local missing case "$_tpacpi" in 127) missing="tpacpi-bat program" ;; 128) missing="acpi_call kernel module" ;; *) missing="" ;; esac if [ -n "$missing" ]; then case "$_natacpi" in "") ;; # undefined 0) ;; # natacpi covers it all 1) printf "Install %s for ThinkPad battery recalibration\n" "$missing" ;; *) printf "Install %s for ThinkPad battery thresholds and recalibration\n" "$missing";; esac fi if [ "$_tpsmapi" = "128" ]; then printf "Install tp-smapi kernel modules for extended battery status (e.g. the cycle count)\n" fi return 0 } ukui-power-manager/3rd/tlp/bat.d/40-sony0000664000175000017500000004041315167661430016645 0ustar fengfeng#!/bin/sh # sony - Battery Plugin for Sony laptops w/ sony_laptop driver # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat # --- Hardware Detection readonly BATDRV_SONY_MD=/sys/devices/platform/sony-laptop batdrv_is_sony () { # check if kernel module loaded # rc: 0=Sony, 1=other hardware [ -d $BATDRV_SONY_MD ] } # --- Plugin API functions readonly BATDRV_SONY_BLE="${BATDRV_SONY_MD}/battery_care_limiter" batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $_batdrv_kmod # # 1. check for vendor specific kernel api # --> retval $_natacpi: # 0=thresholds/ # 32=disabled/ # 128=no kernel support/ # 254=laptop not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi # # 3. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 4. define battery care limiter config, sysfile and default # conig suffix (BAT0 --> retval $_bt_cfg_bat, # sysfile --> retval $_bf_stop, # default --> retval $_bt_def_stop; _batdrv_plugin="sony" _batdrv_kmod="sony_laptop" # kernel module for natacpi # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! batdrv_is_sony; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_match" return 1 fi fi # presume no features at all _natacpi=128 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _batteries="" _bt_cfg_bat="BAT0" # all batteries share the BAT0 config parameter _bf_stop="" _bt_def_stop=100 # iterate batteries local bd bs for bd in "$ACPIBATDIR"/BAT[01]; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi fi done # check for vendor specific kernel api if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 elif [ -f "$BATDRV_SONY_BLE" ] && readable_sysf "$BATDRV_SONY_BLE"; then # sysfile exists and is actually readable _natacpi=0 _bm_thresh="natacpi" _bf_stop="$BATDRV_SONY_BLE" elif [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then # simulate api _natacpi=0 _bm_thresh="natacpi" _bf_stop="$BATDRV_SONY_BLE" else # nothing detected _natacpi=254 fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; thresh=$_bm_thresh; bf_stop=$_bf_stop" return 0 } batdrv_select_battery () { # determine battery acpidir # $1: BAT0/BAT1/DEF # global params: $_batdrv_plugin, $_batteries # # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0/BAT1; # $_bd_read: directory with battery data sysfiles; # prerequisite: batdrv_init() # defaults _bat_str="" # no bat _bd_read="" # no directory local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]")" # validate battery param case "$bat" in DEF) # 1st battery is default _bat_str="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then _bat_str="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # determine battery directory _bd_read="$ACPIBATDIR/$_bat_str" echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; bd_read=$_bd_read;" return 0 } batdrv_read_threshold () { # read and print charge threshold (stop only) # global params: $_batdrv_plugin, $_bm_thresh, $_bf_stop # out: threshold 50/80/100/"" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local out="" rc=0 out="$X_THRESH_SIMULATE_STOP" if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold.simulate: bf_stop=$_bf_stop; out=$out; rc=$rc" return 0 fi if [ "$_bm_thresh" = "natacpi" ]; then out=$(read_sysf "$_bf_stop") || rc=4 else # no threshold api rc=255 fi # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold: bf_stop=$_bf_stop; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write charge thresholds for a battery # use pre-determined method and sysfiles from global parms # $1: new start threshold -- unused dummy for plugin api compatibility # $2: new stop threshold 50/80/100/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bat_str, $_bt_cfg_bat, $_bf_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold out of range or non-numeric/ # 4=threshold read error/ # 5=threshold write error # prerequisite: batdrv_init(), batdrv_select_battery() local new_stop=${2:-} local verb=${3:-0} local old_stop local sony_stop # insert defaults [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds local rc if [ -n "$4" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # stop: check for 3 digits max, ensure 50, 80 or 100 if ! is_uint "$new_stop" 3 || \ ! wordinlist "$new_stop" "50 80 100"; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": care limiter not specified or invalid (must be 50, 80 or 100). Skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": care limiter not specified or invalid (must be 50, 80 or 100). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: care limiter (%s) not specified or invalid (must be 50, 80 or 100). Aborted.\n" "$new_stop" 1>&2 fi ;; esac return 2 fi # convention to disable the stop threshold is 100 --> translate to 0 for Sony if [ "$new_stop" = "100" ]; then sony_stop="0" else sony_stop="$new_stop" fi # read active stop threshold value if ! old_stop=$(batdrv_read_threshold); then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).read_error: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) echo_message "Error: could not read current care limiter. Skipped." ;; 2) printf "Error: could not read current care limiter. Aborted.\n" 1>&2 ;; esac return 4 fi # write new threshold if [ "$verb" = "2" ]; then printf "Setting temporary charge threshold for all batteries:\n" fi local rc=0 if [ "$old_stop" != "$sony_stop" ]; then # new threshold differs from effective one --> write it write_sysf "$sony_stop" "$_bf_stop" || rc=5 echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).write: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$sony_stop; rc=$rc" case $verb in 2) if [ $rc -eq 0 ]; then printf " care limiter = %d\n" "$new_stop" else printf " care limiter = %d (Error: write failed)\n" "$new_stop" 1>&2 fi ;; 1) if [ $rc -gt 0 ]; then echo_message "Error: writing care limiter failed." fi ;; esac else echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).no_change: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$sony_stop" if [ "$verb" = "2" ]; then printf " care limiter = %d (no change)\n" "$new_stop" fi fi return $rc } batdrv_chargeonce () { # function not implemented for Sony laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.charge_once.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # apply configured battery life extender from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local stop_thresh if batdrv_select_battery "DEF"; then eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "DEF" "$stop_thresh" 1 1 fi return 0 } batdrv_read_force_discharge () { # function not implemented for Sony laptops echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge.not_implemented" return 255 } batdrv_write_force_discharge () { # function not implemented for Sony laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented for Sony laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented for Sony laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented for Sony laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_bm_thresh, $_natacpi, $_bd_read, $_bf_stop # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" if [ "$_bm_thresh" = "natacpi" ]; then printf "Supported features: charge threshold\n" else printf "Supported features: none available\n" fi printf "Driver usage:\n" # vendor specific kernel api case $_natacpi in 0) printf "* vendor (%s) = active (charge threshold)\n" "$_batdrv_kmod" ;; 32) printf "* vendor (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* vendor (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* vendor (%s) = inactive (laptop not supported)\n" "$_batdrv_kmod" ;; *) printf "* vendor (%s) = unknown status\n" "$_batdrv_kmod" ;; esac if [ "$_bm_thresh" = "natacpi" ]; then local sp printf "Parameter value range:\n" printf "* STOP_CHARGE_THRESH_BAT0: 50, 80, 100(off) -- battery care limiter\n\n" if sp=$(batdrv_read_threshold); then if [ "$sp" = "0" ]; then printf "%-59s = %6d (100) [%%]\n" "$_bf_stop" "$sp" else printf "%-59s = %6d [%%]\n" "$_bf_stop" "$sp" fi else printf "%-59s = %s [%%]\n" "$_bf_stop" "(not available)" fi fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi # --- show battery features: thresholds # --- show charge level (SOC) and capacity if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # no recommendations for Sony laptops return 0 } ukui-power-manager/3rd/tlp/bat.d/20-huawei0000664000175000017500000004317315167661430017143 0ustar fengfeng#!/bin/sh # 20-huawei - Battery Plugin for Huawei MateBooks w/ huawei_wmi driver # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat # --- Hardware Detection readonly BATDRV_HUAWEI_MD=/sys/devices/platform/huawei-wmi batdrv_is_huawei () { # check if kernel module loaded # rc: 0=Huawei, 1=other hardware [ -d $BATDRV_HUAWEI_MD ] } # --- Plugin API functions readonly BATDRV_HUAWEI_THRESH="${BATDRV_HUAWEI_MD}/charge_control_thresholds" batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $_batdrv_kmod # # 1. check for native kernel acpi (Linux 5.4 or higher required) # --> retval $_natacpi: # 0=thresholds/ # 32=disabled/ # 128=no kernel support/ # 254=laptop not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi # # 3. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 4. determine charge threshold config, sysfile and defaults # sysfile (start and stop threshold) --> retval $_bf_start_stop, # start default --> retval $_bt_def_start, # stop default --> retval $_bt_def_stop; _batdrv_plugin="huawei" _batdrv_kmod="huawei_wmi" # kernel module for natacpi # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! batdrv_is_huawei; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_match" return 1 fi fi # presume no features at all _natacpi=128 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _batteries="" _bt_def_start=0 _bt_def_stop=100 # iterate batteries local bd bs for bd in "$ACPIBATDIR"/BAT[01]; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi fi done # check for vendor specific kernel api if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 elif [ -f "$BATDRV_HUAWEI_THRESH" ] && readable_sysf "$BATDRV_HUAWEI_THRESH"; then # sysfile exists and is actually readable _natacpi=0 _bm_thresh="natacpi" _bf_start_stop="$BATDRV_HUAWEI_THRESH" elif [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then # simulate api _natacpi=0 _bm_thresh="natacpi" _bf_start_stop="$BATDRV_HUAWEI_THRESH" else # nothing detected _natacpi=254 fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; thresh=$_bm_thresh; start_stop=$_bf_start_stop;" return 0 } batdrv_select_battery () { # determine battery acpidir # $1: BAT0/BAT1/DEF # global params: $_batdrv_plugin, $_batteries # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0/BAT1; # $_bt_cfg_bat: config suffix (BAT0/BAT1); # $_bd_read: directory with battery data sysfiles; # prerequisite: batdrv_init() # defaults _bat_str="" # no bat _bd_read="" # no directory local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]")" # validate battery param case "$bat" in DEF) # 1st battery is default _bat_str="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then _bat_str="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # all batteries share the BAT0 config parameters _bt_cfg_bat="BAT0" # determine natacpi sysfiles _bd_read="$ACPIBATDIR/$_bat_str" echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; cfg=$_bt_cfg_bat; bd_read=$_bd_read;" return 0 } batdrv_read_threshold () { # read and print both charge thresholds # global params: $_batdrv_plugin, $_bm_thresh, $_bf_start_stop # out: both thresholds 0..100 separated with a blank/"" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local rc=0 local out="$X_THRESH_SIMULATE_START $X_THRESH_SIMULATE_STOP" if [ "$out" != " " ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold.simulate: bm_thresh=$_bm_thresh; out=$out; rc=$rc" return 0 fi if [ "$_bm_thresh" = "natacpi" ]; then out=$(read_sysf "$_bf_start_stop") || rc=4 else rc=255 fi # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold: bm_thresh=$_bm_thresh; bf_start_stop=$_bf_start_stop; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write both charge thresholds for a battery # use pre-determined method and sysfiles from global parms # $1: new start threshold 0(off)..100/DEF(default) # $2: new stop threshold 0(off)..100(off)/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bm_thresh, $_bt_cfg_bat, $_bf_start_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold(s) out of range or non-numeric/ # 3=minimum start stop diff violated/ # 5=threshold write error # prerequisite: batdrv_init(), batdrv_select_battery() local new_start=${1:-} local new_stop=${2:-} local verb=${3:-0} # insert defaults [ "$new_start" = "DEF" ] && new_start=$_bt_def_start [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds if [ -n "$4" ] && [ -z "$new_start" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).not_configured: cfg=$_bt_cfg_bat" return 1 fi # start: check for 3 digits max, ensure min 0 / max 99 if ! is_uint "$new_start" 3 || \ ! is_within_bounds "$new_start" 0 99; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_start: cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at START_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_start}\": not specified, invalid or out of range (0..99). Skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at START_CHARGE_THRESH_%s=\"%s\": not specified, invalid or out of range (0..99). Aborted.\n" "$_bt_cfg_bat" "$new_start" 1>&2 else printf "Error: start charge threshold (%s) is not specified, invalid or out of range (0..99). Aborted.\n" "$new_start" 1>&2 fi ;; esac return 2 fi # stop: check for 3 digits max, ensure min 1 / max 100 if ! is_uint "$new_stop" 3 || \ ! is_within_bounds "$new_stop" 1 100; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop: cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": not specified, invalid or out of range (1..100). Skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": not specified, invalid or out of range (1..100). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: stop charge threshold (%s) is not specified, invalid or out of range (1..100). Aborted.\n" "$new_stop" 1>&2 fi ;; esac return 2 fi # check start <= stop if [ "$new_start" -gt "$new_stop" ]; then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_diff: cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration: START_CHARGE_THRESH_${_bt_cfg_bat} > STOP_CHARGE_THRESH_${_bt_cfg_bat}. Skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration: START_CHARGE_THRESH_%s > STOP_CHARGE_THRESH_%s. Aborted.\n" "$_bt_cfg_bat" "$_bt_cfg_bat" 1>&2 else printf "Error: start threshold > stop threshold. Aborted.\n" 1>&2 fi ;; esac return 3 fi # write new thresholds if [ "$verb" = "2" ]; then printf "Setting temporary charge thresholds:\n" fi local rc=0 local new_threshs="$new_start $new_stop" write_sysf "$new_threshs" "$_bf_start_stop" || rc=5 echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4): cfg=$_bt_cfg_bat; new=$new_threshs; rc=$rc" case $verb in 2) if [ $rc -eq 0 ]; then printf " %s = %d, %s = %d\n" start "$new_start" stop "$new_stop" else printf " %s = %d, %s = %d (Error: write failed)\n" start "$new_start" stop "$new_stop" 1>&2 fi ;; 1) if [ $rc -gt 0 ]; then echo_message "Error: writing charge thresholds failed." fi ;; esac return $rc } batdrv_chargeonce () { # function not implemented for Huawei MateBooks # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.charge_once.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # apply configured stop thresholds from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local start_thresh stop_thresh if batdrv_select_battery "DEF"; then eval start_thresh="\$START_CHARGE_THRESH_${_bt_cfg_bat}" eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "$start_thresh" "$stop_thresh" 1 1 fi return 0 } batdrv_read_force_discharge () { # function not implemented for Huawei MateBooks # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge.not_implemented" return 255 } batdrv_write_force_discharge () { # function not implemented for Huawei MateBooks # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented for Huawei MateBooks # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented for Huawei MateBooks # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented for Huawei MateBooks # global param: $_batdrv_plugin # prerequisite: batdrv_init() # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_natacpi, $_bd_read, $_bf_start_stop # prerequisite: batdrv_init() local verbose=${1:-0} local threshs printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" if [ "$_bm_thresh" = "natacpi" ]; then printf "Supported features: charge thresholds\n" else printf "Supported features: none available\n" fi printf "Driver usage:\n" # native kernel ACPI battery API case $_natacpi in 0) printf "* vendor (%s) = active (charge thresholds)\n" "$_batdrv_kmod" ;; 32) printf "* vendor (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* vendor (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* vendor (%s) = inactive (laptop not supported)\n" "$_batdrv_kmod" ;; *) printf "* vendor (%s) = unknown status\n" "$_batdrv_kmod" ;; esac if [ "$_bm_thresh" = "natacpi" ]; then printf "Parameter value ranges:\n" printf "* START_CHARGE_THRESH_BAT0: 0(default)..99\n" printf "* STOP_CHARGE_THRESH_BAT0: 1..100(default)\n\n" if threshs=$(batdrv_read_threshold); then case "$threshs" in "0 0"|"0 100") printf "%-59s = %s [%%] (disabled)\n" "$_bf_start_stop" "$threshs" ;; *) printf "%-59s = %s [%%]\n" "$_bf_start_stop" "$threshs" ;; esac else printf "%-59s = %s\n" "$_bf_start_stop" "(not available)" fi fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi # --- show charge level (SOC) and capacity lf=0 if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # no recommendations for Huawei MateBooks return 0 } ukui-power-manager/3rd/tlp/bat.d/15-lenovo0000664000175000017500000004030515167661430017161 0ustar fengfeng#!/bin/sh # 25-ideapad - Battery Plugin for Lenovo laptops w/ ideapad_laptop driver # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat # --- Hardware Detection readonly BATDRV_LENOVO_MD=/sys/bus/platform/drivers/ideapad_acpi batdrv_is_ideapad () { # check if kernel module loaded # rc: 0=Ideapad, 1=other hardware [ -d $BATDRV_LENOVO_MD ] } # --- Plugin API functions readonly BATDRV_LENOVO_CMODE="${BATDRV_LENOVO_MD}/VPC2004:00/conservation_mode" batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $batdrv_kmod # # 1. check for vendor specific kernel api (Linux 4.14 or higher required) # --> retval $_natacpi: # 0=thresholds/ # 32=disabled/ # 128=no kernel support/ # 254=laptop not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi # # 3. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 4. define conservation mode config, sysfile and default # config suffix (BAT0) --> retval $_bt_cfg_bat, # sysfile --> retval $_bf_stop, # default --> retval $_bt_def_stop; _batdrv_plugin="lenovo" _batdrv_kmod="ideapad_laptop" # kernel module for natacpi # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! batdrv_is_ideapad; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_match" return 1 fi fi # presume no features at all _natacpi=128 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _batteries="" _bt_cfg_bat="BAT0" # all batteries share the BAT0 config parameter _bf_stop="" _bt_def_stop=0 # iterate batteries local bd bs for bd in "$ACPIBATDIR"/BAT[01]; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi fi done # check for vendor specific kernel api if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 elif [ -f "$BATDRV_LENOVO_CMODE" ] && readable_sysf "$BATDRV_LENOVO_CMODE"; then # sysfile exists and is actually readable _natacpi=0 _bm_thresh="natacpi" _bf_stop="$BATDRV_LENOVO_CMODE" elif [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then # simulate api _natacpi=0 _bm_thresh="natacpi" _bf_stop="$BATDRV_LENOVO_CMODE" else # nothing detected _natacpi=254 fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; thresh=$_bm_thresh; bf_stop=$_bf_stop" return 0 } batdrv_select_battery () { # determine battery acpidir # $1: BAT0/BAT1/DEF # global params: $_batdrv_plugin, $_batteries # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0/BAT1; # $_bd_read: directory with battery data sysfiles; # prerequisite: batdrv_init() # defaults _bat_str="" # no bat _bd_read="" # no directory local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]")" # validate battery param case "$bat" in DEF) # 1st battery is default _bat_str="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then _bat_str="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # determine natacpi sysfiles _bd_read="$ACPIBATDIR/$_bat_str" echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; cfg=$_bt_cfg_bat; bd_read=$_bd_read;" return 0 } batdrv_read_threshold () { # read and print charge threshold (stop only) # global params: $_batdrv_plugin, $_bf_stop # out: threshold 0/1/"" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local out="" rc=0 out="$X_THRESH_SIMULATE_STOP" if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold.simulate: bf_stop=$_bf_stop; out=$out; rc=$rc" return 0 fi if [ "$_bm_thresh" = "natacpi" ]; then out=$(read_sysf "$_bf_stop") || rc=4 else # no threshold api rc=255 fi # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold: bf_stop=$_bf_stop; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write charge thresholds for a battery # use pre-determined method and sysfiles from global parms # $1: new start threshold -- unused dummy for plugin api compatibility # $2: new stop threshold 0/1/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bat_str, $_bt_cfg_bat, $_bf_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold out of range or non-numeric/ # 4=threshold read error/ # 5=threshold write error # prerequisite: batdrv_init(), batdrv_select_battery() local new_stop=${2:-} local verb=${3:-0} local old_stop # insert defaults [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds local rc if [ -n "$4" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # stop: check for 3 digits max, ensure 0 or 1 if ! is_uint "$new_stop" 3 || \ ! is_within_bounds "$new_stop" 0 1; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop. bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": conservation mode not specified or invalid (must be 0 or 1). Skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": conservation mode not specified or invalid (must be 0 or 1). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: conservation mode (%s) not specified or invalid (must be 0 or 1). Aborted.\n" "$new_stop" 1>&2 fi ;; esac return 2 fi # read active stop threshold value if ! old_stop=$(batdrv_read_threshold); then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).read_error: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) echo_message "Error: could not read current conservation mode. Skipped." ;; 2) printf "Error: could not read current conservation mode. Aborted.\n" 1>&2 ;; esac return 4 fi # write new threshold if [ "$verb" = "2" ]; then printf "Setting temporary charge threshold for all batteries:\n" fi local rc=0 if [ "$old_stop" != "$new_stop" ]; then # new threshold differs from effective one --> write it write_sysf "$new_stop" "$_bf_stop" || rc=5 echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).write: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop; rc=$rc" case $verb in 2) if [ $rc -eq 0 ]; then printf " conservation mode = %d\n" "$new_stop" else printf " conservation mode = %d (Error: write failed)\n" "$new_stop" 1>&2 fi ;; 1) if [ $rc -gt 0 ]; then echo_message "Error: writing conservation mode failed." fi ;; esac else echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).no_change: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop" if [ "$verb" = "2" ]; then printf " conservation mode = %d (no change)\n" "$new_stop" fi fi return $rc } batdrv_chargeonce () { # function not implemented for Lenovo laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.charge_once.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # apply configured conservation mode from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local stop_thresh if batdrv_select_battery "DEF"; then eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "DEF" "$stop_thresh" 1 1 fi return 0 } batdrv_read_force_discharge () { # function not implemented for Lenovo laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge.not_implemented" return 255 } batdrv_write_force_discharge () { # function not implemented for Lenovo laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented for Lenovo laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented for Lenovo laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented for Lenovo laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_natacpi, $_bm_thresh, $_bd_read, $_bf_stop # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" if [ "$_bm_thresh" = "natacpi" ]; then printf "Supported features: charge threshold\n" else printf "Supported features: none available\n" fi printf "Driver usage:\n" # vendor specific kernel api case $_natacpi in 0) printf "* vendor (%s) = active (charge threshold)\n" "$_batdrv_kmod" ;; 32) printf "* vendor (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* vendor (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* vendor (%s) = inactive (laptop not supported)\n" "$_batdrv_kmod" ;; *) printf "* vendor (%s) = unknown status\n" "$_batdrv_kmod" ;; esac if [ "$_bm_thresh" = "natacpi" ]; then local th sfx= printf "Parameter value range:\n" printf "* STOP_CHARGE_THRESH_BAT0: 0(off), 1(on) -- battery conservation mode\n\n" if th=$(batdrv_read_threshold); then case $th in 0) sfx=" (off)" ;; 1) sfx=" (on)" ;; *) sfx=" (invalid)" ;; esac printf "%-59s = %d%s\n" "$_bf_stop" "$th" "$sfx" else printf "%-59s = %s\n" "$_bf_stop" "(not available)" fi fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi # --- show charge level (SOC) and capacity if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # no recommendations for Lenovo laptops return 0 } ukui-power-manager/3rd/tlp/bat.d/90-generic0000664000175000017500000001643215167661430017302 0ustar fengfeng#!/bin/sh # 90-generic - Battery plugin catchall for laptops that either not provide # a kernel interface for battery care or TLP doesn't support it yet. # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat batdrv_init () { # detect hardware and initialize driver # rc: 0 (catchall) # retval: $_batdrv_plugin # # 1. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 2. designate battery care as unsupported # reading battery data --> retval $_bm_read = "none", # reading/writing charging thresholds --> retval $_bm_thresh = "none", # reading/writing force discharge --> retval $_bm_dischg = "none": _batdrv_plugin="generic" # iterate batteries local bs bd _batteries="" for bd in "$ACPIBATDIR"/*; do if [ "$(read_sysf "$bd/type")" = "Battery" ] \ && [ "$(read_sysf "$bd/present")" = "1" ]; then bs=${bd##/*/} # ignore atypical power supplies and batteries printf '%s\n' "$bs" | grep -E -q "$RE_PS_IGNORE" && continue # record detected batteries and directories if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi fi done # shellcheck disable=SC2034 _bm_read="none" # shellcheck disable=SC2034 _bm_thresh="none" # shellcheck disable=SC2034 _bm_dischg="none" # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries" # catchall: always return 0 return 0 } batdrv_select_battery () { # determine battery acpidir # $1: battery # retval: $_bd_read: directory with battery data sysfiles local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$1" | tr "[:lower:]" "[:upper:]")" _bd_read="$ACPIBATDIR/$bat" return 0 } batdrv_read_threshold () { # function not implemented for generic hardware echo_debug "bat" "batdrv.${_batdrv_plugin}.read_treshold.not_implemented" return 255 } batdrv_write_thresholds () { # function not implemented for generic hardware echo_debug "bat" "batdrv.${_batdrv_plugin}.write_tresholds.not_implemented" return 255 } batdrv_chargeonce () { # function not implemented for generic hardware echo_debug "bat" "batdrv.${_batdrv_plugin}.chargeonce.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # function not implemented for generic hardware echo_debug "bat" "batdrv.${_batdrv_plugin}.apply_configured_thresholds.not_implemented" return 255 } batdrv_read_force_discharge () { # function not implemented for generic hardware echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge.not_implemented" return 255 } batdrv_write_force_discharge () { # function not implemented for generic hardware echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented for generic hardware echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented for generic hardware echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented for generic hardware # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery data # $1: 1=verbose # global param: $_batteries # rc: 0=ok/1=no batteries specified local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" printf "Supported features: none available\n\n" local bat lf local bcnt=0 local ed ef en local efsum=0 local ensum=0 if [ -z "$_batteries" ]; then printf "+++ Battery Status\n" printf "No batteries detected.\n\n" return 1 fi for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi printparm "%-59s = ##%6d## [%%]" "$_bd_read/charge_control_start_threshold" "not available" printparm "%-59s = ##%6d## [%%]" "$_bd_read/charge_control_end_threshold" "not available" printf "\n" # charge + capacity lf=0 if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # no recommendations for generic hardware return 0 } ukui-power-manager/3rd/tlp/bat.d/10-thinkpad-legacy0000664000175000017500000010431715167661430020722 0ustar fengfeng#!/bin/sh # 10-thinkpad-legacy - Battery Plugin for ThinkPads using tp_smapi # for thresholds and forced discharge, # i.e. X201/T410 and older. # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat, 05-thinkpad # --- Plugin API functions batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $batdrv_kmod # # 1. check for tp_smapi external kernel module # --> retval $_tpsmapi # 0=supported/ # 32=disabled/ # 64=tp_smapi module not loaded/ # 128=tp_smapi module not installed/ # 254=ThinkPad not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi/tpacpi/tpsmapi # # 3. determine sysfile basenames for tpsmapi # start threshold --> retval $_bn_start, # stop threshold --> retval $_bn_stop, # force discharge --> retval $_bn_dischg; # # 4. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 5. define charge threshold defaults # start threshold --> retval $_bt_def_start, # stop threshold --> retval $_bt_def_stop; _batdrv_plugin="thinkpad-legacy" _batdrv_kmod="tp_smapi" # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! check_thinkpad; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.not_a_thinkpad" return 1 elif ! supports_tpsmapi_only; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.unsupported_model" return 1 fi fi # presume no features at all _tpsmapi=254 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _bn_start="start_charge_thresh" _bn_stop="stop_charge_thresh" _bn_dischg="force_discharge" _batteries="" _bt_def_start=96 _bt_def_stop=100 local bs bd done=0 if [ "$TPSMAPI_ENABLE" = "0" ]; then # tp-smapi disabled by configuration _tpsmapi=32 else # probe tp_smapi external kernel module load_modules "$MOD_TPSMAPI" if [ -d "$SMAPIBATDIR" ]; then # module loaded --> tp-smapi available # enumerate tp_smapi batteries # note: tp_smapi battery names may diverge from ACPI names, # refer to https://github.com/linrunner/TLP/issues/714 for bd in "$SMAPIBATDIR"/BAT[01]; do if [ "$(read_sysf "$bd/installed")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi # skip tp-smapi detection for 2nd battery [ $done -eq 1 ] && continue done=1 if readable_sysf "$bd/$_bn_start" \ && readable_sysf "$bd/$_bn_stop" \ && readable_sysf "$bd/$_bn_dischg"; then # tp-smapi sysfiles are actually readable _tpsmapi=0 _bm_read="tpsmapi" _bm_thresh="tpsmapi" _bm_dischg="tpsmapi" fi fi done # quit if no battery detected, there is no point in activating the plugin if [ -z "$_batteries" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_batteries" return 2 fi fi fi if [ "$_tpsmapi" -ne 0 ]; then # tp-smapi unavailable or disabled # enumerate ACPI batteries so that at least tlp-stat -b can show their data _batteries="" for bd in "$ACPIBATDIR"/BAT[01]; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi fi done # quit if no battery detected, there is no point in activating the plugin if [ -z "$_batteries" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_batteries" return 2 fi # remaining tp-smapi inavailability cases if [ "$_tpsmapi" -eq 32 ]; then : # tp-smapi disabled elif $MODINFO "$MOD_TPSMAPI" > /dev/null 2>&1; then # module installed but not loaded _tpsmapi=64 else # module neither installed nor builtin _tpsmapi=128 fi fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; tpsmapi=$_tpsmapi" echo_debug "bat" "batdrv_init.${_batdrv_plugin}: read=$_bm_read; thresh=$_bm_thresh; bn_start=$_bn_start; bn_stop=$_bn_stop; dischg=$_bm_dischg; bn_dischg=$_bn_dischg" return 0 } batdrv_select_battery () { # determine battery sysfiles and bat index # $1: BAT0/BAT1/DEF # global params: $_batdrv_plugin, $_batteries, $_bm_thresh, $_bm_dischg # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0/BAT1; # $_bat_idx: 1/2; # $_bd_read: directory with battery data sysfiles; # $_bf_start: sysfile for start threshold; # $_bf_stop: sysfile for stop threshold; # $_bf_dischg: sysfile for force discharge # prerequisite: batdrv_init() # defaults _bat_idx=0 # no index _bat_str="" # no bat _bd_read="" # no directories _bf_start="" _bf_stop="" _bf_dischg="" local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]")" # validate battery param local bs case "$bat" in DEF) # 1st battery is default bs="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then bs="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # determine bat index for main/aux distinction _bat_str="$bs" case $bs in BAT0) _bat_idx=1 ;; BAT1) _bat_idx=2 ;; esac # config suffix equals battery name _bt_cfg_bat="$_bat_str" # determine tp-smapi sysfiles if [ "$_bm_thresh" = "tpsmapi" ]; then _bf_start="$SMAPIBATDIR/$bs/$_bn_start" _bf_stop="$SMAPIBATDIR/$bs/$_bn_stop" fi if [ "$_bm_dischg" = "tpsmapi" ]; then _bf_dischg="$SMAPIBATDIR/$bs/$_bn_dischg" fi case "$_bm_read" in natacpi) _bd_read="$ACPIBATDIR/$bs" ;; tpsmapi) _bd_read="$SMAPIBATDIR/$bs" ;; esac echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; cfg=$_bt_cfg_bat; bat_idx=$_bat_idx; bd_read=$_bd_read; bf_start=$_bf_start; bf_stop=$_bf_stop; bf_dischg=$_bf_dischg" return 0 } batdrv_read_threshold () { # read and print charge threshold # $1: start/stop # $2: 0=api/1=tlp-stat output # global params: $_batdrv_plugin, $_bm_thresh, $_bf_start, $_bf_stop # out: # - api: 0..100/"" on error # - tlp-stat: 0..100/"(not available)" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local bf out="" rc=0 case $1 in start) out="$X_THRESH_SIMULATE_START" ;; stop) out="$X_THRESH_SIMULATE_STOP" ;; esac if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1, $2).simulate: bm_thresh=$_bm_thresh; bf=$bf; out=$out; rc=$rc" return 0 fi case $_bm_thresh in tpsmapi) # read threshold from sysfile case $1 in start) bf=$_bf_start ;; stop) bf=$_bf_stop ;; esac if ! out=$(read_sysf "$bf"); then # not readable/non-existent if [ "$2" != "1" ]; then out="" else out="(not available)" fi rc=4 fi ;; *) # no threshold api rc=255 ;; esac # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else if [ "$2" = "1" ]; then printf "(not available)\n" fi rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1, $2): bm_thresh=$_bm_thresh; bf=$bf; bat_idx=$_bat_idx; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write both charge thresholds for a battery # use pre-determined method and sysfiles from global parms # $1: new start threshold 0(disabled)..99/DEF(default) # $2: new stop threshold 1..100/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bm_thresh, $_bat_str, $_bt_cfg_bat, $_bf_start, $_bf_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold(s) out of range or non-numeric/ # 3=minimum start stop diff violated/ # 4=threshold read error/ # 5=threshold write error # prerequisite: batdrv_init(), batdrv_select_battery() local new_start=${1:-} local new_stop=${2:-} local verb=${3:-0} local old_start old_stop # insert defaults [ "$new_start" = "DEF" ] && new_start=$_bt_def_start [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds local rc if [ -n "$4" ] && [ -z "$new_start" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # start: check for 3 digits max, ensure min 2 / max 96 if ! is_uint "$new_start" 3 || \ ! is_within_bounds "$new_start" 2 96; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_start: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at START_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_start}\": not specified, invalid or out of range (2..96). Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at START_CHARGE_THRESH_%s=\"%s\": not specified, invalid or out of range (2..96). Aborted.\n" "$_bt_cfg_bat" "$new_start" 1>&2 else printf "Error: start charge threshold (%s) for %s is not specified, invalid or out of range (2..96). Aborted.\n" "$new_start" "$_bat_str" 1>&2 fi ;; esac return 2 fi # stop: check for 3 digits max, ensure min 6 / max 100 if ! is_uint "$new_stop" 3 || \ ! is_within_bounds "$new_stop" 6 100; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": not specified, invalid or out of range (6..100). Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": not specified, invalid or out of range (6..100). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: stop charge threshold (%s) for %s is not specified, invalid or out of range (6..100). Aborted.\n" "$new_stop" "$_bat_str" 1>&2 fi ;; esac return 2 fi # check minimum start - stop difference if [ $((new_start + 4)) -gt "$new_stop" ]; then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_diff: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration: START_CHARGE_THRESH_${_bt_cfg_bat} > STOP_CHARGE_THRESH_${_bt_cfg_bat} - 4. Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration: START_CHARGE_THRESH_%s > STOP_CHARGE_THRESH_%s - 4. Aborted.\n" "$_bt_cfg_bat" "$_bt_cfg_bat" 1>&2 else printf "Error: start threshold > stop threshold - 4 for %s. Aborted.\n" "$_bat_str" 1>&2 fi ;; esac return 3 fi # read active threshold values if ! old_start=$(batdrv_read_threshold start 0) || \ ! old_stop=$(batdrv_read_threshold stop 0); then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).read_error: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) echo_message "Error: could not read current charge threshold(s) for $_bat_str. Battery skipped." ;; 2) printf "Error: could not read current charge threshold(s) for %s. Aborted.\n" "$_bat_str" 1>&2 ;; esac return 4 fi # determine write sequence because driver's intrinsic boundary conditions # must be met in all write stages: # - tp-smapi: start <= stop - 4 (changes value for compliance) local rc=0 steprc tseq if [ "$new_start" -gt "$old_stop" ]; then tseq="stop start" else tseq="start stop" fi # write new thresholds in determined sequence if [ "$verb" = "2" ]; then printf "Setting temporary charge thresholds for %s:\n" "$_bat_str" fi for step in $tseq; do local old_thresh new_thresh steprc case $step in start) old_thresh=$old_start new_thresh=$new_start ;; stop) old_thresh=$old_stop new_thresh=$new_stop ;; esac if [ "$old_thresh" != "$new_thresh" ]; then # new threshold differs from effective one --> write it case $step in start) write_sysf "$new_thresh" "$_bf_start" ;; stop) write_sysf "$new_thresh" "$_bf_stop" ;; esac steprc=$?; [ $steprc -ne 0 ] && [ $rc -eq 0 ] && rc=5 echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).$step.write: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_thresh; new=$new_thresh; steprc=$steprc" case $verb in 2) if [ $steprc -eq 0 ]; then printf " %-5s = %3d\n" "$step" "$new_thresh" else printf " %-5s = %3d (Error: write failed)\n" "$step" "$new_thresh" 1>&2 fi ;; 1) if [ $steprc -gt 0 ]; then echo_message "Error: writing $step charge threshold for $_bat_str failed." fi ;; esac else echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).$step.no_change: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_thresh; new=$new_thresh" if [ "$verb" = "2" ]; then printf " %-5s = %3d (no change)\n" "$step" "$new_thresh" fi fi done # for step echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).complete: bat=$_bat_str; cfg=$_bt_cfg_bat; rc=$rc" return $rc } batdrv_chargeonce () { # charge battery to stop threshold once # use pre-determined method and sysfiles from global parms # global params: $_batdrv_plugin, $_bm_thresh, $_bat_str, $_bf_start, $_bf_stop # rc: 0=ok/ # 2=charge level read error # 3=charge level too high/ # 4=threshold read error/ # 5=threshold write error/ # 6=stop threshold too low # prerequisite: batdrv_init(), batdrv_select_battery() local ccharge cur_stop efull enow temp_start local rc=0 if ! cur_stop=$(batdrv_read_threshold stop 0); then printf "Error: reading stop charge threshold for %s failed. Aborted.\n" "$_bat_str" 1>&2 echo_debug "bat" "batdrv.${_batdrv_plugin}.chargeonce($_bat_str).thresh_unknown: stop=$cur_stop; rc=4" return 4 elif [ "$cur_stop" -lt 6 ]; then printf "Error: the %s stop charge threshold is %s. " "$_bat_str" "$ccharge" 1>&2 printf "For this command to work, it must be 6 at least.\n" 1>&2 echo_debug "bat" "batdrv.${_batdrv_plugin}.chargeonce($_bat_str).stop_thresh_too_low: stop=$cur_stop; rc=6" return 6 fi # get current charge level (in %) case $_bm_read in tpsmapi) # use tp-smapi sysfile ccharge=$(read_sysval "$_bd_read/remaining_percent") || ccharge=-1 ;; esac if [ "$ccharge" -eq -1 ] ; then printf "Error: cannot determine charge level for %s.\n" "$_bat_str" 1>&2 echo_debug "bat" "batdrv.${_batdrv_plugin}.chargeonce($_bat_str).charge_level_unknown: enow=$enow; efull=$efull; rc=2" return 2 fi temp_start=$(( cur_stop - 4 )) if [ "$ccharge" -gt "$temp_start" ]; then printf "Error: the %s charge level is %s%%. " "$_bat_str" "$ccharge" 1>&2 printf "For this command to work, it must not exceed %s%% (stop threshold - 4).\n" "$temp_start" 1>&2 echo_debug "bat" "batdrv.${_batdrv_plugin}.chargeonce($_bat_str).charge_level_too_high: soc=$ccharge; stop=$cur_stop; rc=3" return 3 fi printf "Setting temporary charge threshold for %s:" "$_bat_str" case $_bm_thresh in tpsmapi) write_sysf "$temp_start" "$_bf_start" || rc=5 ;; esac if [ $rc -eq 0 ]; then printf " start = %3d\n" "$temp_start" else printf " start = %3d (Error: write failed)\n" "$temp_start" 1>&2 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.chargeonce($_bat_str): soc=$ccharge; start=$temp_start; stop=$cur_stop; rc=$rc" return $rc } batdrv_apply_configured_thresholds () { # apply configured stop thresholds from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local bat start_thresh stop_thresh for bat in BAT0 BAT1; do if batdrv_select_battery "$bat"; then eval start_thresh="\$START_CHARGE_THRESH_${_bt_cfg_bat}" eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "$start_thresh" "$stop_thresh" 1 1 fi done return 0 } batdrv_read_force_discharge () { # read and print force discharge state # $1: 0=api/1=tlp-stat output # global params: $_batdrv_plugin, $_bm_dischg, $_bat_str, $_bf_dischg, $_bat_idx # - api: 0=off/1=on/"" on error # - tlp-stat: 0=off/1=on/"(not available)" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local rc=0 out="" case $_bm_dischg in tpsmapi) # read force discharge from sysfile out=$(read_sysf "$_bf_dischg"); if ! out=$(read_sysf "$_bf_dischg"); then # not readable/non-existent if [ "$1" = "1" ]; then out="(not available)" fi rc=4 fi ;; *) # no discharge api if [ "$1" = "1" ]; then out="(not available)" fi rc=255 ;; esac printf "%s" "$out" if [ "$rc" -gt 0 ]; then # log output in the error case only echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge($_bat_str): bm_dischg=$_bm_dischg; bf_dischg=$_bf_dischg; out=$out; rc=$rc" fi return $rc } batdrv_write_force_discharge () { # write force discharge state # $1: 0=off/1=on/255=no api # global params: $_batdrv_plugin, $_bat_str, $_bat_idx, $_bm_dischg, $_bf_dischg # rc: 0=done/5=write error # prerequisite: batdrv_init(), batdrv_select_battery() local rc=0 case $_bm_dischg in tpsmapi) # write force_discharge write_sysf "$1" "$_bf_dischg" || rc=5 ;; *) # no discharge api rc=255 ;; esac echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge($_bat_str, $1): bm_dischg=$_bm_dischg; bf_dischg=$_bf_dischg; bat_idx=$_bat_idx; rc=$rc" return $rc } batdrv_cancel_force_discharge () { # trap: called from batdrv_discharge # global params: $_batdrv_plugin, $_bat_str # prerequisite: batdrv_discharge() batdrv_write_force_discharge 0 unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.cancelled($_bat_str)" printf " Cancelled.\n" do_exit 0 } batdrv_force_discharge_active () { # check if battery is in 'force_discharge' state # global params: $_batdrv_plugin, $_bat_str, $_bm_read, $_bd_read # rc: 0=discharging/1=not discharging or read error # prerequisite: batdrv_init(), batdrv_select_battery() local rc=1 soc # check if force_discharge is on [ "$(batdrv_read_force_discharge 0)" = "1" ] && rc=0 if [ $rc -eq 0 ] && ! get_sys_power_supply; then # AC unplugged --> cancel discharge batdrv_write_force_discharge 0 rc=1 fi soc=$(read_sysf "$_bd_read/remaining_percent") echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active($_bat_str): bm_read=$_bm_read; soc=$soc; rc=$rc" return $rc } batdrv_discharge () { # discharge battery # global params: $_batdrv_plugin, $_bm_dischg, $_bat_str, $_bd_read, $_bf_dischg # rc: 0=done/1=malfunction/2=not emptied/3=ac removed/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local rc rp wt # start discharge if ! batdrv_write_force_discharge 1; then echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.force_discharge_malfunction($_bat_str)" printf "Error: discharge %s malfunction -- check your hardware (battery, charger).\n" "$_bat_str" 1>&2 return 1 fi trap batdrv_cancel_force_discharge INT # enable ^C hook rc=0; rp=0 # wait for start == while status not "discharging" -- 15.0 sec timeout printf "Initiating discharge of battery %s " "$_bat_str" wt=15 while ! batdrv_force_discharge_active && [ $wt -gt 0 ] ; do sleep 1 printf "." wt=$((wt - 1)) done printf "\n" if batdrv_force_discharge_active; then # discharge initiated sucessfully --> wait for completion == while status "discharging" echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.running($_bat_str)" while batdrv_force_discharge_active; do clear printf "Currently discharging battery %s:\n" "$_bat_str" # show current battery state case $_bm_read in tpsmapi) # use tp-smapi sysfiles printf "voltage = %6s [mV]\n" "$(read_sysf "$_bd_read/voltage")" printf "remaining capacity = %6s [mWh]\n" "$(read_sysf "$_bd_read/remaining_capacity")" rp=$(read_sysf "$_bd_read/remaining_percent") printf "remaining percent = %6s [%%]\n" "$rp" printf "remaining time = %6s [min]\n" "$(read_sysf "$_bd_read/remaining_running_time_now")" printf "power = %6s [mW]\n" "$(read_sysf "$_bd_read/power_avg")" printf "state = %s\n" "$(read_sysf "$_bd_read/state")" ;; esac printf "force discharge = %s\n" "$(batdrv_read_force_discharge 0)" printf "Press Ctrl+C to cancel.\n" sleep 5 done unlock_tlp tlp_discharge # read charge level one last time case $_bm_read in tpsmapi) # use tp-smapi sysfiles rp=$(read_sysf "$_bd_read/remaining_percent") ;; esac if [ "$rp" -gt 0 ]; then # battery not emptied --> determine cause get_sys_power_supply # shellcheck disable=SC2154 if [ "$_syspwr" -eq 1 ]; then # system on battery --> AC power removed echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.ac_removed($_bat_str)" printf "Warning: battery %s was not discharged completely -- AC/charger removed.\n" "$_bat_str" 1>&2 rc=3 else # discharging terminated by unknown reason echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_emptied($_bat_str)" printf "Error: battery %s was not discharged completely i.e. terminated by the firmware -- check your hardware (battery, charger).\n" "$_bat_str" 1>&2 rc=2 fi fi else # discharge malfunction --> cancel discharge and abort batdrv_write_force_discharge 0 echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.malfunction($_bat_str)" printf "Error: discharge %s malfunction -- check your hardware (battery, charger).\n" "$_bat_str" 1>&2 rc=1 fi trap - INT # remove ^C hook if [ $rc -eq 0 ]; then printf "\n" printf "Done: battery %s was completely discharged.\n" "$_bat_str" echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.complete($_bat_str)" fi return $rc } batdrv_show_battery_data () { # output battery data # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_tpsmapi, $_bm_thresh, $_bd_read, $_bf_start, $_bf_stop, $_bf_dischg # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" local fs="" [ "$_bm_thresh" != "none" ] && fs="charge thresholds" if [ "$_bm_dischg" != "none" ]; then [ -n "$fs" ] && fs="${fs}, " fs="${fs}recalibration" fi [ -n "$fs" ] || fs="none available" printf "Supported features: %s\n" "$fs" printf "Driver usage:\n" # ThinkPad-specific battery API case $_tpsmapi in 0) printf "* tp-smapi (%s) = active " "$_batdrv_kmod"; print_methods_per_driver "tpsmapi" ;; 32) printf "* tp-smapi (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 64) printf "* tp-smapi (%s) = inactive (kernel module 'tp_smapi' load error)\n" "$_batdrv_kmod" ;; 128) printf "* tp-smapi (%s) = inactive (kernel module 'tp_smapi' not installed)\n" "$_batdrv_kmod" ;; 254) printf "* tp-smapi (%s) = inactive (ThinkPad not supported)\n" "$_batdrv_kmod" ;; *) printf "* tp-smapi (%s) = unknown status\n" "$_batdrv_kmod" ;; esac if [ "$_bm_thresh" != "none" ]; then printf "Parameter value ranges:\n" printf "* START_CHARGE_THRESH_BAT0/1: 2..96(default)\n" printf "* STOP_CHARGE_THRESH_BAT0/1: 6..100(default)\n" fi printf "\n" local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate detected batteries batdrv_select_battery "$bat" case $_bat_idx in 1) printf "+++ ThinkPad Battery Status: %s (Main / Internal)\n" "$bat" ;; 2) printf "+++ ThinkPad Battery Status: %s (Ultrabay / Slice / Replaceable)\n" "$bat" ;; 0) printf "+++ ThinkPad Battery Status: %s\n" "$bat" ;; esac # --- show basic data case $_bm_read in natacpi) # no tp-smapi --> use ACPI data printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi ;; # natacpi tpsmapi) # tp-smapi active printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model" printparm "%-59s = ##%s##" "$_bd_read/manufacture_date" printparm "%-59s = ##%s##" "$_bd_read/first_use_date" printparm "%-59s = ##%6d##" "$_bd_read/cycle_count" if [ -f "$_bd_read/temperature" ]; then # shellcheck disable=SC2046 perl -e 'printf ("%-59s = %6d [°C]\n", "'"$_bd_read/temperature"'", '$(read_sysval "$_bd_read/temperature")' / 1000.0);' fi printparm "%-59s = ##%6d## [mWh]" "$_bd_read/design_capacity" printparm "%-59s = ##%6d## [mWh]" "$_bd_read/last_full_capacity" printparm "%-59s = ##%6d## [mWh]" "$_bd_read/remaining_capacity" printparm "%-59s = ##%6d## [%%]" "$_bd_read/remaining_percent" printparm "%-59s = ##%6s## [min]" "$_bd_read/remaining_running_time_now" printparm "%-59s = ##%6s## [min]" "$_bd_read/remaining_charging_time" printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_avg" print_batstate "$_bd_read/state" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/design_voltage" printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage" printparm "%-59s = ##%6s## [mV]" "$_bd_read/group0_voltage" printparm "%-59s = ##%6s## [mV]" "$_bd_read/group1_voltage" printparm "%-59s = ##%6s## [mV]" "$_bd_read/group2_voltage" printparm "%-59s = ##%6s## [mV]" "$_bd_read/group3_voltage" printf "\n" fi # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/design_capacity") ef=$(read_sysval "$_bd_read/last_full_capacity") en=$(read_sysval "$_bd_read/remaining_capacity") efsum=$((efsum + ef)) ensum=$((ensum + en)) ;; # tp-smapi esac # $_bm_read # --- show battery features: thresholds, force_discharge local lf=0 if [ "$_bm_thresh" = "tpsmapi" ]; then printf "%-59s = %6s [%%]\n" "$_bf_start" "$(batdrv_read_threshold start 1)" printf "%-59s = %6s [%%]\n" "$_bf_stop" "$(batdrv_read_threshold stop 1)" lf=1 fi if [ "$_bm_dischg" = "tpsmapi" ]; then printf "%-59s = %6s\n" "$_bf_dischg" "$(batdrv_read_force_discharge 1)" lf=1 fi [ $lf -gt 0 ] && printf "\n" # --- show charge level (SOC) and capacity lf=0 if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # output Legacy ThinkPad specific recommendations # prerequisite: batdrv_init() if [ "$_tpsmapi" = "128" ]; then printf "Install tp-smapi kernel modules for ThinkPad battery thresholds and recalibration\n" fi return 0 } ukui-power-manager/3rd/tlp/bat.d/30-samsung0000664000175000017500000004020315167661430017326 0ustar fengfeng#!/bin/sh # samsung - Battery Plugin for Samsung laptops w/ samsung_laptop driver # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat # --- Hardware Detection readonly BATDRV_SAMSUNG_MD=/sys/devices/platform/samsung batdrv_is_samsung () { # check if kernel module loaded # rc: 0=Samsung, 1=other hardware [ -d $BATDRV_SAMSUNG_MD ] } # --- Plugin API functions readonly BATDRV_SAMSUNG_BLE="${BATDRV_SAMSUNG_MD}/battery_life_extender" batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $batdrv_kmod # # 1. check for vendor specific kernel api # --> retval $_natacpi: # 0=thresholds/ # 32=disabled/ # 128=no kernel support/ # 254=laptop not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi # # 3. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 4. define battery life extender config, sysfile and default # config suffix (BAT0) --> retval $_bt_cfg_bat, # sysfile --> retval $_bf_stop, # default --> retval $_bt_def_stop; _batdrv_plugin="samsung" _batdrv_kmod="samsung_laptop" # kernel module for natacpi # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! batdrv_is_samsung; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_match" return 1 fi fi # presume no features at all _natacpi=128 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _batteries="" _bt_cfg_bat="BAT0" # all batteries share the BAT0 config parameter _bf_stop="" _bt_def_stop=0 # iterate batteries local bd bs for bd in "$ACPIBATDIR"/BAT[01]; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi fi done # check for vendor specific kernel api if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 elif [ -f "$BATDRV_SAMSUNG_BLE" ] && readable_sysf "$BATDRV_SAMSUNG_BLE"; then # sysfile exists and is actually readable _natacpi=0 _bm_thresh="natacpi" _bf_stop="$BATDRV_SAMSUNG_BLE" elif [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then # simulate api _natacpi=0 _bm_thresh="natacpi" _bf_stop="$BATDRV_SAMSUNG_BLE" else # nothing detected _natacpi=254 fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; thresh=$_bm_thresh; bf_stop=$_bf_stop" return 0 } batdrv_select_battery () { # determine battery acpidir # $1: BAT0/BAT1/DEF # global params: $_batdrv_plugin, $_batteries # # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0/BAT1; # $_bd_read: directory with battery data sysfiles; # prerequisite: batdrv_init() # defaults _bat_str="" # no bat _bd_read="" # no directory local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]")" # validate battery param case "$bat" in DEF) # 1st battery is default _bat_str="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then _bat_str="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # determine natacpi sysfiles _bd_read="$ACPIBATDIR/$_bat_str" echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; bd_read=$_bd_read;" return 0 } batdrv_read_threshold () { # read and print charge threshold (stop only) # global params: $_batdrv_plugin, $_bm_thresh, $_bf_stop # out: threshold 0/1/"" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local out="" rc=0 out="$X_THRESH_SIMULATE_STOP" if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold.simulate: bf_stop=$_bf_stop; out=$out; rc=$rc" return 0 fi if [ "$_bm_thresh" = "natacpi" ]; then out=$(read_sysf "$_bf_stop") || rc=4 else # no threshold api rc=255 fi # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold: bf_stop=$_bf_stop; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write charge thresholds for a battery # use pre-determined method and sysfiles from global parms # $1: new start threshold -- unused dummy for plugin api compatibility # $2: new stop threshold 0/1/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bat_str, $_bt_cfg_bat, $_bf_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold out of range or non-numeric/ # 4=threshold read error/ # 5=threshold write error # prerequisite: batdrv_init(), batdrv_select_battery() local new_stop=${2:-} local verb=${3:-0} local old_stop # insert defaults [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds local rc if [ -n "$4" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # stop: check for 3 digits max, ensure 0 or 1 if ! is_uint "$new_stop" 3 || \ ! is_within_bounds "$new_stop" 0 1; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": life extender not specified or invalid (must be 0 or 1). Skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": life extender not specified or invalid (must be 0 or 1). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: life extender (%s) not specified or invalid (must be 0 or 1). Aborted.\n" "$new_stop" 1>&2 fi ;; esac return 2 fi # read active stop threshold value if ! old_stop=$(batdrv_read_threshold); then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).read_error: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) echo_message "Error: could not read current life extender. Skipped." ;; 2) printf "Error: could not read current life extender. Aborted.\n" 1>&2 ;; esac return 4 fi # write new threshold if [ "$verb" = "2" ]; then printf "Setting temporary charge threshold for all batteries:\n" fi local rc=0 if [ "$old_stop" != "$new_stop" ]; then # new threshold differs from effective one --> write it write_sysf "$new_stop" "$_bf_stop" || rc=5 echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).write: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop; rc=$rc" case $verb in 2) if [ $rc -eq 0 ]; then printf " life extender = %d\n" "$new_stop" else printf " life extender = %d (Error: write failed)\n" "$new_stop" 1>&2 fi ;; 1) if [ $rc -gt 0 ]; then echo_message "Error: writing life extender failed." fi ;; esac else echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).no_change: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop" if [ "$verb" = "2" ]; then printf " life extender = %d (no change)\n" "$new_stop" fi fi return $rc } batdrv_chargeonce () { # function not implemented for Samsung laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.charge_once.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # apply configured battery life extender from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local stop_thresh if batdrv_select_battery "DEF"; then eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "DEF" "$stop_thresh" 1 1 fi return 0 } batdrv_read_force_discharge () { # function not implemented for Samsung laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge.not_implemented" return 255 } batdrv_write_force_discharge () { # function not implemented for Samsung laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented for Samsung laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented for Samsung laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented for Samsung laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_bm_thresh, $_natacpi, $_bd_read, $_bf_stop # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" if [ "$_bm_thresh" = "natacpi" ]; then printf "Supported features: charge threshold\n" else printf "Supported features: none available\n" fi printf "Driver usage:\n" # vendor specific kernel api case $_natacpi in 0) printf "* vendor (%s) = active (charge threshold)\n" "$_batdrv_kmod" ;; 32) printf "* vendor (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* vendor (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* vendor (%s) = inactive (laptop not supported)\n" "$_batdrv_kmod" ;; *) printf "* vendor (%s) = unknown status\n" "$_batdrv_kmod" ;; esac if [ "$_bm_thresh" = "natacpi" ]; then local th sfx= printf "Parameter value range:\n" printf "* STOP_CHARGE_THRESH_BAT0: 0(off), 1(on) -- -- battery life extender\n\n" if th=$(batdrv_read_threshold); then case $th in 0) sfx=" (100%)" ;; 1) sfx=" (80%)" ;; *) sfx=" (invalid)";; esac printf "%-59s = %d%s\n" "$_bf_stop" "$th" "$sfx" else printf "%-59s = %s\n" "$_bf_stop" "(not available)" fi fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi # --- show charge level (SOC) and capacity lf=0 if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # no recommendations for Samsung laptops return 0 } ukui-power-manager/3rd/tlp/bat.d/25-msi0000664000175000017500000004700415167661430016453 0ustar fengfeng#!/bin/sh # 55-msi - Battery Plugin for MSI laptops w/ msi_ec driver # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat # --- Hardware Detection readonly BATDRV_MSI_MD=/sys/module/msi_ec batdrv_is_msi () { # check if vendor specific kernel module is loaded # rc: 0=ok, 1=other hardware [ -d $BATDRV_MSI_MD ] } # --- Plugin API functions batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $_batdrv_kmod # # 1. check for native kernel acpi (Linux 5.4 or higher required) # --> retval $_natacpi: # 0=thresholds/ # 32=disabled/ # 128=no kernel support/ # 254=laptop not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi # # 3. define sysfile basenames for natacpi # start threshold --> retval $_bn_start, # stop threshold --> retval $_bn_stop, # # 4. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 5. define charge threshold defaults # start threshold --> retval $_bt_def_start, # stop threshold --> retval $_bt_def_stop; _batdrv_plugin="msi" _batdrv_kmod="msi_ec" # kernel module for natacpi # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! batdrv_is_msi; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_match" return 1 fi fi # presume no features at all _natacpi=128 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _bn_start="" _bn_stop="" _batteries="" # vendor defaults _bt_def_start=90 _bt_def_stop=100 # iterate batteries and check for native kernel ACPI local bd bs local done=0 for bd in "$ACPIBATDIR"/BAT[01]; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi # skip natacpi detection for 2nd and subsequent batteries [ $done -eq 1 ] && continue done=1 if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 continue fi if [ -f "$bd/charge_control_start_threshold" ] \ && [ -f "$bd/charge_control_end_threshold" ]; then # threshold sysfiles exist _bn_start="charge_control_start_threshold" _bn_stop="charge_control_end_threshold" _natacpi=254 else # nothing detected _natacpi=254 continue fi if readable_sysf "$bd/$_bn_start" \ && readable_sysf "$bd/$_bn_stop"; then # threshold sysfiles are actually readable _natacpi=0 _bm_thresh="natacpi" fi fi done # quit if no battery detected, there is no point in activating the plugin if [ -z "$_batteries" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_batteries" return 2 fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; thresh=$_bm_thresh; bn_start=$_bn_start; bn_stop=$_bn_stop; dischg=$_bm_dischg" return 0 } batdrv_select_battery () { # determine battery acpidir and sysfiles # $1: BAT0/BAT1/DEF # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0/BAT1; # $_bd_read: directory with battery data sysfiles; # $_bt_cfg_bat: config suffix (BAT0/BAT1); # $_bf_start: sysfile for stop threshold; # $_bf_stop: sysfile for stop threshold; # prerequisite: batdrv_init() # defaults _bat_str="" # no bat _bt_cfg_bat="" _bd_read="" # no directory _bf_start="" _bf_stop="" local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]")" # validate battery param case "$bat" in DEF) # 1st battery is default _bat_str="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then _bat_str="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # config suffix equals battery name _bt_cfg_bat="$_bat_str" # determine natacpi sysfiles _bd_read="$ACPIBATDIR/$_bat_str" if [ "$_bm_thresh" = "natacpi" ]; then _bf_start="$ACPIBATDIR/$_bat_str/$_bn_start" _bf_stop="$ACPIBATDIR/$_bat_str/$_bn_stop" fi echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; cfg=$_bt_cfg_bat; bd_read=$_bd_read; bf_start=$_bf_start; bf_stop=$_bf_stop" return 0 } batdrv_read_threshold () { # read and print charge threshold # $1: start/stop # $2: 0=api/1=tlp-stat output # global params: $_batdrv_plugin, $_bm_thresh, $_bf_start, $_bf_stop # out: # - api: 0..100/"" on error # - tlp-stat: 0..100/"(not available)" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local bf out="" rc=0 case $1 in start) out="$X_THRESH_SIMULATE_START" ;; stop) out="$X_THRESH_SIMULATE_STOP" ;; esac if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1, $2).simulate: bm_thresh=$_bm_thresh; bf=$bf; out=$out; rc=$rc" return 0 fi if [ "$_bm_thresh" = "natacpi" ]; then # read threshold from sysfile case $1 in start) bf=$_bf_start ;; stop) bf=$_bf_stop ;; esac if ! out=$(read_sysf "$bf"); then # not readable/non-existent if [ "$2" != "1" ]; then out="" else out="(not available)" fi rc=4 fi else # no threshold api if [ "$2" = "1" ]; then out="(not available)" fi rc=255 fi # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else if [ "$2" = "1" ]; then printf "(not available)\n" fi rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1, $2): bm_thresh=$_bm_thresh; bf=$bf; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write both charge thresholds for a battery # use pre-determined method and sysfiles from global parms # note: the MSI hardware allows to choose only the stop threshold value, start is always = stop - 10 # $1: new start threshold 0..90/DEF(default) # $2: new stop threshold 10..100/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bm_thresh, $_bat_str, $_bt_cfg_bat, $_bf_start, $_bf_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold(s) out of range or non-numeric/ # 3=minimum start stop diff violated/ # 4=threshold read error/ # 5=threshold write error # prerequisite: batdrv_init(), batdrv_select_battery() local new_start=${1:-} local new_stop=${2:-} local verb=${3:-0} local old_stop local nom_start # insert defaults [ "$new_start" = "DEF" ] && new_start=$_bt_def_start [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds local rc if [ -n "$4" ] && [ -z "$new_start" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # stop: check for 3 digits max, ensure min 10 / max 100 if ! is_uint "$new_stop" 3 || \ ! is_within_bounds "$new_stop" 10 100; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": not specified, invalid or out of range (10..100). Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": not specified, invalid or out of range (10..100). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: stop charge threshold (%s) for %s is not specified, invalid or out of range (10..100). Aborted.\n" "$new_stop" "$_bat_str" 1>&2 fi ;; esac return 2 fi # hardware constraint: start = stop - 10 nom_start=$((new_stop - 10)) # start: silently ignore non-numeric or invalid threshold, substitute it with stop - 10 if ! is_uint "$new_start" 3 || [ "$new_start" -ne "$nom_start" ]; then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_start: bat=$_bat_str; cfg=$_bt_cfg_bat; nom=$nom_start" new_start="$nom_start" fi # read active stop threshold value if ! old_stop=$(batdrv_read_threshold stop 0); then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).read_error: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) echo_message "Error: could not read current stop charge threshold for $_bat_str. Battery skipped." ;; 2) printf "Error: could not read current stop charge threshold for %s. Aborted.\n" "$_bat_str" 1>&2 ;; esac return 4 fi # write new thresholds if [ "$verb" = "2" ]; then printf "Setting temporary charge thresholds for %s:\n" "$_bat_str" fi local rc=0 steprc if [ "$old_stop" != "$new_stop" ]; then # new stop threshold differs from effective one --> write it write_sysf "$new_stop" "$_bf_stop" steprc=$?; [ $steprc -ne 0 ] && rc=5 echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).stop.write: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop; steprc=$steprc" case $verb in 2) if [ $steprc -eq 0 ]; then printf " %-5s = %3d\n" "stop" "$new_stop" else printf " %-5s = %3d (Error: write failed)\n" "stop" "$new_stop" 1>&2 fi ;; 1) if [ $steprc -gt 0 ]; then echo_message "Error: writing stop charge threshold for $_bat_str failed." fi ;; esac # write start threshold only when simulating MSI hardware if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then write_sysf "$new_start" "$_bf_start" fi if [ "$verb" = "2" ]; then printf " %-5s = %3d (due to hardware constraint)\n" "start" "$new_start" fi else echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).stop.no_change: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop" if [ "$verb" = "2" ]; then printf " %-5s = %3d (no change)\n" "stop" "$new_stop" printf " %-5s = %3d (no change)\n" "start" "$new_start" fi fi echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).complete: bat=$_bat_str; cfg=$_bt_cfg_bat; rc=$rc" return $rc } batdrv_chargeonce () { # function not implemented for MSI laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.charge_once.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # apply configured stop thresholds from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local bat start_thresh stop_thresh for bat in BAT0 BAT1; do if batdrv_select_battery "$bat"; then eval start_thresh="\$START_CHARGE_THRESH_${_bt_cfg_bat}" eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "$start_thresh" "$stop_thresh" 1 1 fi done return 0 } batdrv_read_force_discharge () { # function not implemented for MSI laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge.not_implemented" return 255 } batdrv_write_force_discharge () { # function not implemented for MSI laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented for MSI laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented for MSI laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented for MSI laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_bm_thresh, $_bd_read, $_bf_start, $_bf_stop, $_bf_dischg # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" if [ "$_bm_thresh" != "none" ]; then printf "Supported features: charge thresholds\n" else printf "Supported features: none available\n" fi printf "Driver usage:\n" # native kernel ACPI battery API case $_natacpi in 0) printf "* natacpi (%s) = active (charge thresholds)\n" "$_batdrv_kmod" ;; 32) printf "* natacpi (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* natacpi (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* natacpi (%s) = inactive (laptop not supported)\n" "$_batdrv_kmod" ;; *) printf "* natacpi (%s) = unknown status\n" "$_batdrv_kmod" ;; esac if [ "$_bm_thresh" != "none" ]; then printf "Parameter value ranges:\n" printf "* START_CHARGE_THRESH_BAT0/1: don't care (hardware enforces stop - 10)\n" printf "* STOP_CHARGE_THRESH_BAT0/1: 10..100(default)\n" fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi # --- show battery features: thresholds if [ "$_bm_thresh" = "natacpi" ]; then printf "%-59s = %6s [%%]\n" "$_bf_start" "$(batdrv_read_threshold start 1)" printf "%-59s = %6s [%%]\n" "$_bf_stop" "$(batdrv_read_threshold stop 1)" printf "\n" fi # --- show charge level (SOC) and capacity lf=0 if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # no recommendations return 0 } ukui-power-manager/3rd/tlp/bat.d/50-toshiba0000664000175000017500000004251715167661430017316 0ustar fengfeng#!/bin/sh # 50-toshiba - Battery Plugin for Toshiba (now Dynabook) laptops # w/ toshiba_acpi driver # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat # --- Hardware Detection readonly BATDRV_TOSHIBA_MD=/sys/module/toshiba_acpi batdrv_is_toshiba () { # check if kernel module loaded # rc: 0=Toshiba, 1=other hardware [ -d $BATDRV_TOSHIBA_MD ] } # --- Plugin API functions batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $_batdrv_kmod # # 1. check for native kernel acpi (Linux 6.0 or higher required) # --> retval $_natacpi: # 0=thresholds/ # 32=disabled/ # 128=no kernel support/ # 254=laptop not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi # # 3. define sysfile basename for natacpi # stop threshold --> retval $_bn_stop, # # 4. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 5. define charge threshold defaults # stop threshold --> retval $_bt_def_stop; _batdrv_plugin="toshiba" _batdrv_kmod="toshiba_acpi" # kernel module for natacpi # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! batdrv_is_toshiba; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_match" return 1 fi fi # presume no features at all _natacpi=128 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _bn_stop="" _batteries="" _bt_def_stop=100 # iterate batteries and check for native kernel ACPI local bd bs local done=0 for bd in "$ACPIBATDIR"/BAT[01]; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi # skip natacpi detection for 2nd and subsequent batteries [ $done -eq 1 ] && continue done=1 if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 elif [ -f "$bd/charge_control_end_threshold" ] && readable_sysf "$bd/charge_control_end_threshold"; then # sysfile for stop threshold exists and is actually readable _natacpi=0 _bm_thresh="natacpi" _bn_stop="charge_control_end_threshold" elif [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then # simulate api _natacpi=0 _bm_thresh="natacpi" _bn_stop="charge_control_end_threshold" else # nothing detected _natacpi=254 fi fi done # quit if no battery detected, there is no point in activating the plugin if [ -z "$_batteries" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_batteries" return 2 fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; thresh=$_bm_thresh; stop=$_bn_stop;" return 0 } batdrv_select_battery () { # determine battery acpidir and sysfile # $1: BAT0/BAT1/DEF # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0/BATC/BATT/BAT1; # $_bt_cfg_bat: config suffix (BAT0/BAT1); # $_bd_read: directory with battery data sysfiles; # $_bf_stop: sysfile for stop threshold; # prerequisite: batdrv_init() # defaults _bat_str="" # no bat _bt_cfg_bat="" _bd_read="" # no directory _bf_stop="" local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]")" # validate battery param case "$bat" in DEF) # 1st battery is default _bat_str="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then _bat_str="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # config suffix equals battery name _bt_cfg_bat="$_bat_str" # determine natacpi sysfile _bd_read="$ACPIBATDIR/$_bat_str" if [ "$_bm_thresh" = "natacpi" ]; then _bf_stop="$ACPIBATDIR/$_bat_str/$_bn_stop" fi echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; cfg=$_bt_cfg_bat; bd_read=$_bd_read; bf_stop=$_bf_stop" return 0 } batdrv_read_threshold () { # read and print charge threshold (stop only) # $1: 0=api/1=tlp-stat output # global params: $_batdrv_plugin, $_bm_thresh, $_bf_stop # out: # - api: 80,100/"" on error # - tlp-stat: 80,100/"(not available)" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local out="" rc=0 out="$X_THRESH_SIMULATE_STOP" if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1).simulate: bm_thresh=$_bm_thresh; bf_stop=$_bf_stop; out=$out; rc=$rc" return 0 fi if [ "$_bm_thresh" = "natacpi" ]; then if ! out=$(read_sysf "$_bf_stop"); then # not readable/non-existent if [ "$1" != "1" ]; then out="" else out="(not available)" fi rc=4 fi else # no threshold api if [ "$1" = "1" ]; then out="(not available)" fi rc=255 fi # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else if [ "$1" = "1" ]; then printf "(not available)\n" fi rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1): bm_thresh=$_bm_thresh; bf_stop=$_bf_stop; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write charge thresholds for a battery # use pre-determined method and sysfiles from global parms # $1: new start threshold -- unused dummy for plugin api compatibility # $2: new stop threshold 80,100/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bm_thresh, $_bat_str, $_bt_cfg_bat, $_bf_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold out of range or non-numeric/ # 4=threshold read error/ # 5=threshold write error # prerequisite: batdrv_init(), batdrv_select_battery() local new_stop=${2:-} local verb=${3:-0} local old_stop # insert defaults [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds if [ -n "$4" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # stop: check for 3 digits max, ensure 80 or 100 if ! is_uint "$new_stop" 3 || ! wordinlist "$new_stop" "80 100"; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": not specified or invalid (must be 80 or 100). Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": not specified or invalid (must be 80 or 100). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: stop charge threshold (%s) for %s is not specified or invalid (must be 80 or 100). Aborted.\n" "$new_stop" "$_bat_str" 1>&2 fi ;; esac return 2 fi # read active threshold value if ! old_stop=$(batdrv_read_threshold stop 0); then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).read_error: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) echo_message "Error: could not read current stop charge threshold for $_bat_str. Battery skipped." ;; 2) printf "Error: could not read current stop charge threshold for %s. Aborted.\n" "$_bat_str" 1>&2 ;; esac return 4 fi # write new threshold if [ "$verb" = "2" ]; then printf "Setting temporary charge threshold for %s:\n" "$_bat_str" fi local rc=0 if [ "$old_stop" != "$new_stop" ]; then # new threshold differs from effective one --> write it write_sysf "$new_stop" "$_bf_stop" || rc=5 echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).write: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop; rc=$rc" case $verb in 2) if [ $rc -eq 0 ]; then printf " stop = %3d\n" "$new_stop" else printf " stop = %3d (Error: write failed)\n" "$new_stop" 1>&2 fi ;; 1) if [ $rc -gt 0 ]; then echo_message "Error: writing stop charge threshold for $_bat_str failed." fi ;; esac else echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).no_change: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_stop; new=$new_stop" if [ "$verb" = "2" ]; then printf " stop = %3d (no change)\n" "$new_stop" 1>&2 fi fi return $rc } batdrv_chargeonce () { # function not implemented for Toshiba / Dynabook laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.charge_once.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # apply configured stop thresholds from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local bat stop_thresh for bat in BAT0 BAT1; do if batdrv_select_battery "$bat"; then eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "DEF" "$stop_thresh" 1 1; rc=$? fi done return 0 } batdrv_read_force_discharge () { # function not implemented for Toshiba / Dynabook laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge.not_implemented" return 255 } batdrv_write_force_discharge () { # function not implemented for Toshiba / Dynabook laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented for Toshiba / Dynabook laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented for Toshiba / Dynabook laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented for Toshiba / Dynabook laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_bd_read, $_bf_stop # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" if [ "$_bm_thresh" = "natacpi" ]; then printf "Supported features: charge threshold\n" else printf "Supported features: none available\n" fi printf "Driver usage:\n" # native kernel ACPI battery API case $_natacpi in 0) printf "* natacpi (%s) = active (charge threshold)\n" "$_batdrv_kmod" ;; 32) printf "* natacpi (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* natacpi (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* natacpi (%s) = inactive (laptop not supported)\n" "$_batdrv_kmod" ;; *) printf "* natacpi (%s) = unknown status\n" "$_batdrv_kmod" ;; esac if [ "$_bm_thresh" = "natacpi" ]; then printf "Parameter value range:\n" printf "* STOP_CHARGE_THRESH_BAT0/1: 80(on), 100(off)\n" fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi # --- show battery features: thresholds if [ "$_bm_thresh" = "natacpi" ]; then printf "%-59s = %6s [%%]\n" "$_bf_stop" "$(batdrv_read_threshold 1)" printf "\n" fi # --- show charge level (SOC) and capacity lf=0 if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # no recommendations for Toshiba / Dynabook laptops return 0 } ukui-power-manager/3rd/tlp/bat.d/TEMPLATE0000664000175000017500000005437715167661430016665 0ustar fengfeng#!/bin/sh # Battery Plugin TEMPLATE for laptops providing standard sysfs nodes for # charge thresholds: # * /sys/class/power_supply/BAT0/charge_control_start_threshold # * /sys/class/power_supply/BAT0/charge_control_end_threshold # # IMPORTANT: customize at least all places marked with "TEMPLATE" # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat # --- Hardware Detection readonly BATDRV_TEMPLATE_MD=/sys/module/TEMPLATE_MODULE_DIR batdrv_is_TEMPLATE () { # check if vendor specific kernel module is loaded # rc: 0=ok, 1=other hardware [ -d $BATDRV_TEMPLATE_MD ] } # --- Plugin API functions batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $_batdrv_kmod # # 1. check for native kernel acpi (TEMPLATE: Linux m.n or higher required) # --> retval $_natacpi: # 0=thresholds/ # 32=disabled/ # 128=no kernel support/ # 254=laptop not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi # # 3. define sysfile basenames for natacpi # start threshold --> retval $_bn_start, # stop threshold --> retval $_bn_stop, # discharge --> retval $_bn_discharge # # 4. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 5. define charge threshold defaults # start threshold --> retval $_bt_def_start, # stop threshold --> retval $_bt_def_stop; _batdrv_plugin="TEMPLATE" _batdrv_kmod="TEMPLATE_MOD" # kernel module for natacpi # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! batdrv_is_TEMPLATE; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_match" return 1 fi fi # presume no features at all _natacpi=128 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _bn_start="" _bn_stop="" _bn_dischg="" _batteries="" # TEMPLATE: customize to vendor defaults _bt_def_start=96 _bt_def_stop=100 # iterate batteries and check for native kernel ACPI local bd bs local done=0 # TEMPLATE: customize battery names if necessary for bd in "$ACPIBATDIR"/BAT[01]; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi # skip natacpi detection for 2nd and subsequent batteries [ $done -eq 1 ] && continue done=1 if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 continue fi if [ -f "$bd/charge_control_start_threshold" ] \ && [ -f "$bd/charge_control_end_threshold" ]; then # threshold sysfiles exist _bn_start="charge_control_start_threshold" _bn_stop="charge_control_end_threshold" _natacpi=254 else # nothing detected _natacpi=254 continue fi if readable_sysf "$bd/$_bn_start" \ && readable_sysf "$bd/$_bn_stop"; then # threshold sysfiles are actually readable _natacpi=0 _bm_thresh="natacpi" fi fi done # quit if no battery detected, there is no point in activating the plugin if [ -z "$_batteries" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_batteries" return 2 fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; thresh=$_bm_thresh; bn_start=$_bn_start; bn_stop=$_bn_stop; dischg=$_bm_dischg; bn_dischg=$_bn_dischg" return 0 } batdrv_select_battery () { # determine battery acpidir and sysfiles # $1: BAT0/BAT1/DEF # global params: $_batdrv_plugin, $_batteries, $_bn_start, $_bn_stop, $_bn_dischg # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0/BAT1/; # $_bt_cfg_bat: config suffix (BAT0/BAT1); # $_bd_read: directory with battery data sysfiles; # $_bf_start: sysfile for start threshold; # $_bf_stop: sysfile for stop threshold; # prerequisite: batdrv_init() # defaults _bat_str="" # no bat _bt_cfg_bat="" _bd_read="" # no directory _bf_start="" _bf_stop="" local bat="$1" # convert battery param to uppercase # TEMPLATE: omit the following line for lower case battery device names bat="$(printf '%s' "$bat" | tr "[:lower:]" "[:upper:]")" # validate battery param case "$bat" in DEF) # 1st battery is default _bat_str="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then _bat_str="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # TEMPLATE: assume config suffix matches battery name, i.e. works for BAT0/BAT1 only _bt_cfg_bat="$_bat_str" # determine natacpi sysfiles _bd_read="$ACPIBATDIR/$_bat_str" if [ "$_bm_thresh" = "natacpi" ]; then _bf_start="$ACPIBATDIR/$_bat_str/$_bn_start" _bf_stop="$ACPIBATDIR/$_bat_str/$_bn_stop" fi echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; cfg=$_bt_cfg_bat; bd_read=$_bd_read; bf_start=$_bf_start; bf_stop=$_bf_stop" return 0 } batdrv_read_threshold () { # read and print charge threshold # $1: start/stop # $2: 0=api/1=tlp-stat output # global params: $_batdrv_plugin, $_bm_thresh, $_bf_start, $_bf_stop # out: # - api: 0..100/"" on error # - tlp-stat: 0..100/"(not available)" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local bf out="" rc=0 case $1 in start) out="$X_THRESH_SIMULATE_START" ;; stop) out="$X_THRESH_SIMULATE_STOP" ;; esac if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1, $2).simulate: bm_thresh=$_bm_thresh; bf=$bf; out=$out; rc=$rc" return 0 fi if [ "$_bm_thresh" = "natacpi" ]; then # read threshold from sysfile case $1 in start) bf=$_bf_start ;; stop) bf=$_bf_stop ;; esac if ! out=$(read_sysf "$bf"); then # not readable/non-existent if [ "$2" != "1" ]; then out="" else out="(not available)" fi rc=4 fi else # no threshold api if [ "$2" = "1" ]; then out="(not available)" fi rc=255 fi # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else if [ "$2" = "1" ]; then printf "(not available)\n" fi rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1, $2): bm_thresh=$_bm_thresh; bf=$bf; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write both charge thresholds for a battery # use pre-determined method and sysfiles from global parms # $1: new start threshold 0(disabled)..100/DEF(default) # $2: new stop threshold 0..100/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bm_thresh, $_bat_str, $_bt_cfg_bat, $_bf_start, $_bf_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold(s) out of range or non-numeric/ # 3=minimum start stop diff violated/ # 4=threshold read error/ # 5=threshold write error # prerequisite: batdrv_init(), batdrv_select_battery() local new_start=${1:-} local new_stop=${2:-} local verb=${3:-0} local old_start old_stop # insert defaults [ "$new_start" = "DEF" ] && new_start=$_bt_def_start [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds local rc if [ -n "$4" ] && [ -z "$new_start" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # TEMPLATE: customize boundaries to vendor specs # start: check for 3 digits max, ensure min 0 / max 100 if ! is_uint "$new_start" 3 || \ ! is_within_bounds "$new_start" 0 100; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_start: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at START_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_start}\": not specified, invalid or out of range (0..100). Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at START_CHARGE_THRESH_%s=\"%s\": not specified, invalid or out of range (0..100). Aborted.\n" "$_bt_cfg_bat}" "$new_start" 1>&2 else printf "Error: start charge threshold (%s) for %s is not specified, invalid or out of range (0..100). Aborted.\n" "$new_start" "$_bat_str" 1>&2 fi ;; esac return 2 fi # TEMPLATE: customize boundaries to vendor specs # stop: check for 3 digits max, ensure min 0 / max 100 if ! is_uint "$new_stop" 3 || \ ! is_within_bounds "$new_stop" 0 100; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": not specified, invalid or out of range (0..100). Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": not specified, invalid or out of range (0..100). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: stop charge threshold (%s) for %s is not specified, invalid or out of range (0..100). Aborted.\n" "$new_stop" "$_bat_str" 1>&2 fi ;; esac return 2 fi # TEMPLATE: customize assertion to vendor specs # check start < stop if [ "$new_start" -ge "$new_stop" ]; then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_diff: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration: START_CHARGE_THRESH_${_bt_cfg_bat} >= STOP_CHARGE_THRESH_$_bt_cfg_bat. Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration: START_CHARGE_THRESH_%s >= STOP_CHARGE_THRESH_%s. Aborted.\n" "$_bt_cfg_bat" "$_bt_cfg_bat" 1>&2 else printf "Error: start threshold >= stop threshold for %s. Aborted.\n" "$_bat_str" 1>&2 fi ;; esac return 3 fi # read active threshold values if ! old_start=$(batdrv_read_threshold start 0) || \ ! old_stop=$(batdrv_read_threshold stop 0); then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).read_error: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) echo_message "Error: could not read current charge threshold(s) for $_bat_str. Battery skipped." ;; 2) printf "Error: could not read current charge threshold(s) for %s. Aborted.\n" "$_bat_str" 1>&2 ;; esac return 4 fi # TEMPLATE: customize assertion to vendor specs # determine write sequence too meet boundary condition start < stop # disclaimer: the driver doesn't enforce it but we don't know about the # firmware and it's reasonable anyway local rc=0 steprc tseq if [ "$new_start" -ge "$old_stop" ]; then tseq="stop start" else tseq="start stop" fi # write new thresholds in determined sequence if [ "$verb" = "2" ]; then printf "Setting temporary charge thresholds for %s:\n" "$_bat_str" fi for step in $tseq; do local old_thresh new_thresh steprc case $step in start) old_thresh=$old_start new_thresh=$new_start ;; stop) old_thresh=$old_stop new_thresh=$new_stop ;; esac if [ "$old_thresh" != "$new_thresh" ]; then # new threshold differs from effective one --> write it case $step in start) write_sysf "$new_thresh" "$_bf_start" ;; stop) write_sysf "$new_thresh" "$_bf_stop" ;; esac steprc=$?; [ $steprc -ne 0 ] && rc=5 echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).$step.write: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_thresh; new=$new_thresh; steprc=$steprc" case $verb in 2) if [ $steprc -eq 0 ]; then printf " %-5s = %3d\n" "$step" "$new_thresh" else printf " %-5s = %3d (Error: write failed)\n" "$step" "$new_thresh" 1>&2 fi ;; 1) if [ $steprc -gt 0 ]; then echo_message "Error: writing $step charge threshold for $_bat_str failed." fi ;; esac else echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).$step.no_change: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_thresh; new=$new_thresh" if [ "$verb" = "2" ]; then printf " %-5s = %3d (no change)\n" "$step" "$new_thresh" fi fi done # for step echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).complete: bat=$_bat_str; cfg=$_bt_cfg_bat; rc=$rc" return $rc } batdrv_chargeonce () { # function not implemented # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.charge_once.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # apply configured stop thresholds from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local bat start_thresh stop_thresh for bat in BAT0 BAT1; do if batdrv_select_battery "$bat"; then eval start_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "$start_thresh" "$stop_thresh" 1 1 fi done return 0 } batdrv_read_force_discharge () { # function not implemented # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge.not_implemented" return 255 } batdrv_write_force_discharge () { # function not implemented # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented # global param: $_batdrv_plugin # prerequisite: batdrv_init() # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_bd_read, $_bf_start, $_bf_stop, $_bf_dischg # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" if [ "$_bm_thresh" != "none" ]; then printf "Supported features: charge thresholds\n" else printf "Supported features: none available\n" fi printf "Driver usage:\n" # native kernel ACPI battery API case $_natacpi in 0) printf "* natacpi (%s) = active (charge thresholds)\n" "$_batdrv_kmod" ;; 32) printf "* natacpi (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* natacpi (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* natacpi (%s) = inactive (laptop not supported)\n" "$_batdrv_kmod" ;; *) printf "* natacpi (%s) = unknown status\n" "$_batdrv_kmod" ;; esac # TEMPLATE: customize to vendor specs if [ "$_bm_thresh" != "none" ]; then printf "Parameter value ranges:\n" printf "* START_CHARGE_THRESH_BAT0/1: 0(off)..100\n" printf "* STOP_CHARGE_THRESH_BAT0/1: 0..100(default)\n" fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi # --- show battery features: thresholds if [ "$_bm_thresh" = "natacpi" ]; then printf "%-59s = %6s [%%]\n" "$_bf_start" "$(batdrv_read_threshold start 1)" printf "%-59s = %6s [%%]\n" "$_bf_stop" "$(batdrv_read_threshold stop 1)" printf "\n" fi # --- show charge level (SOC) and capacity lf=0 if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat if [ $bcnt -gt 1 ] && [ $efsum -ne 0 ]; then # more than one battery detected --> show charge total perl -e 'printf ("%-59s = %6.1f [%%]\n", "+++ Charge total", 100.0 * '"$ensum"' / '"$efsum"');' printf "\n" fi return 0 } batdrv_recommendations () { # no recommendations return 0 } ukui-power-manager/3rd/tlp/bat.d/45-system760000664000175000017500000005225115167661430017366 0ustar fengfeng#!/bin/sh # 45-system76 - Battery Plugin for System76 laptops # w/ open source EC firmware and system76_acpi driver # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # Needs: tlp-func-base, 35-tlp-func-batt, tlp-func-stat # --- Hardware Detection readonly BATDRV_SYSTEM76_MD=/sys/module/system76_acpi batdrv_is_system76 () { # check if system76 specific kernel module is loaded # rc: 0=ok, 1=other hardware [ -d $BATDRV_SYSTEM76_MD ] } # --- Plugin API functions batdrv_init () { # detect hardware and initialize driver # rc: 0=matching hardware detected/1=not detected/2=no batteries detected # retval: $_batdrv_plugin, $_batdrv_kmod # # 1. check for native kernel acpi (Linux 5.4 or higher required) # --> retval $_natacpi: # 0=thresholds/ # 32=disabled/ # 128=no kernel support/ # 254=laptop not supported # # 2. determine method for # reading battery data --> retval $_bm_read, # reading/writing charging thresholds --> retval $_bm_thresh, # reading/writing force discharge --> retval $_bm_dischg: # none/natacpi # # 3. define sysfile basenames for natacpi # start threshold --> retval $_bn_start, # stop threshold --> retval $_bn_stop, # # 4. determine present batteries # list of batteries (space separated) --> retval $_batteries; # # 5. define charge threshold defaults # start threshold --> retval $_bt_def_start, # stop threshold --> retval $_bt_def_stop; _batdrv_plugin="system76" _batdrv_kmod="system76_acpi" # kernel module for natacpi # check plugin simulation override and denylist if [ -n "$X_BAT_PLUGIN_SIMULATE" ]; then if [ "$X_BAT_PLUGIN_SIMULATE" = "$_batdrv_plugin" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate" else echo_debug "bat" "batdrv_init.${_batdrv_plugin}.simulate_skip" return 1 fi elif wordinlist "$_batdrv_plugin" "$X_BAT_PLUGIN_DENYLIST"; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.denylist" return 1 else # check if hardware matches if ! batdrv_is_system76; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_match" return 1 fi fi # presume no features at all _natacpi=128 _bm_read="natacpi" _bm_thresh="none" _bm_dischg="none" _bn_start="" _bn_stop="" _batteries="" # vendor defaults _bt_def_start=90 _bt_def_stop=100 # iterate batteries and check for native kernel ACPI local bd bs local done=0 # System76 EC only supports one battery # shellcheck disable=SC2043 for bd in "$ACPIBATDIR"/BAT0; do if [ "$(read_sysf "$bd/present")" = "1" ]; then # record detected batteries and directories bs=${bd##/*/} if [ -n "$_batteries" ]; then _batteries="$_batteries $bs" else _batteries="$bs" fi # skip natacpi detection for 2nd and subsequent batteries [ $done -eq 1 ] && continue done=1 if [ "$NATACPI_ENABLE" = "0" ]; then # natacpi disabled in configuration --> skip actual detection _natacpi=32 continue fi if [ -f "$bd/charge_control_start_threshold" ] \ && [ -f "$bd/charge_control_end_threshold" ]; then # threshold sysfiles exist _bn_start="charge_control_start_threshold" _bn_stop="charge_control_end_threshold" _natacpi=254 else # nothing detected _natacpi=254 continue fi if readable_sysf "$bd/$_bn_start" \ && readable_sysf "$bd/$_bn_stop"; then # threshold sysfiles are actually readable _natacpi=0 _bm_thresh="natacpi" fi fi done # quit if no battery detected, there is no point in activating the plugin if [ -z "$_batteries" ]; then echo_debug "bat" "batdrv_init.${_batdrv_plugin}.no_batteries" return 2 fi # shellcheck disable=SC2034 _batdrv_selected=$_batdrv_plugin echo_debug "bat" "batdrv_init.${_batdrv_plugin}: batteries=$_batteries; natacpi=$_natacpi; thresh=$_bm_thresh; bn_start=$_bn_start; bn_stop=$_bn_stop; dischg=$_bm_dischg" return 0 } batdrv_select_battery () { # determine battery acpidir and sysfiles # $1: BAT0/DEF # # rc: 0=bat exists/1=bat non-existent # retval: $_bat_str: BAT0 # $_bt_cfg_bat: config suffix (BAT0); # $_bd_read: directory with battery data sysfiles; # $_bf_start: sysfile for stop threshold; # $_bf_stop: sysfile for stop threshold; # prerequisite: batdrv_init() # defaults _bat_str="" # no bat _bd_read="" # no directory _bf_start="" _bf_stop="" local bat="$1" # convert battery param to uppercase bat="$(printf '%s' "$1" | tr "[:lower:]" "[:upper:]")" # validate battery param case "$bat" in DEF) # 1st battery is default _bat_str="${_batteries%% *}" ;; *) if wordinlist "$bat" "$_batteries"; then _bat_str="$bat" else # battery not present --> quit echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1).not_present" return 1 fi ;; esac # System76 EC only supports one battery _bt_cfg_bat="BAT0" # determine natacpi sysfiles _bd_read="$ACPIBATDIR/$_bat_str" if [ "$_bm_thresh" = "natacpi" ]; then _bf_start="$ACPIBATDIR/$_bat_str/$_bn_start" _bf_stop="$ACPIBATDIR/$_bat_str/$_bn_stop" fi echo_debug "bat" "batdrv.${_batdrv_plugin}.select_battery($1): bat_str=$_bat_str; cfg=$_bt_cfg_bat; bd_read=$_bd_read; bf_start=$_bf_start; bf_stop=$_bf_stop" return 0 } batdrv_read_threshold () { # read and print charge threshold # $1: start/stop # $2: 0=api/1=tlp-stat output # global params: $_batdrv_plugin, $_bm_thresh, $_bf_start, $_bf_stop # out: # - api: 0..100/"" on error # - tlp-stat: 0..100/"(not available)" on error # rc: 0=ok/4=read error/255=no api # prerequisite: batdrv_init(), batdrv_select_battery() local bf out="" rc=0 case $1 in start) out="$X_THRESH_SIMULATE_START" ;; stop) out="$X_THRESH_SIMULATE_STOP" ;; esac if [ -n "$out" ]; then printf "%s" "$out" echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1, $2).simulate: bm_thresh=$_bm_thresh; bf=$bf; out=$out; rc=$rc" return 0 fi if [ "$_bm_thresh" = "natacpi" ]; then # read threshold from sysfile case $1 in start) bf=$_bf_start ;; stop) bf=$_bf_stop ;; esac if ! out=$(read_sysf "$bf"); then # not readable/non-existent if [ "$2" != "1" ]; then out="" else out="(not available)" fi rc=4 fi else # no threshold api if [ "$2" = "1" ]; then out="(not available)" fi rc=255 fi # "return" threshold if [ "$X_THRESH_SIMULATE_READERR" != "1" ]; then printf "%s" "$out" else if [ "$2" = "1" ]; then printf "(not available)\n" fi rc=4 fi echo_debug "bat" "batdrv.${_batdrv_plugin}.read_threshold($1, $2): bm_thresh=$_bm_thresh; bf=$bf; out=$out; rc=$rc" return $rc } batdrv_write_thresholds () { # write both charge thresholds for a battery # use pre-determined method and sysfiles from global parms # $1: new start threshold 0(disabled)..99/DEF(default) # $2: new stop threshold 1..100/DEF(default) # $3: 0=quiet/1=output parameter errors/2=output progress and errors # $4: non-empty string indicates thresholds stem from configuration # global params: $_batdrv_plugin, $_bm_thresh, $_bat_str, $_bt_cfg_bat, $_bf_start, $_bf_stop # rc: 0=ok/ # 1=not configured/ # 2=threshold(s) out of range or non-numeric/ # 3=minimum start stop diff violated/ # 4=threshold read error/ # 5=threshold write error # prerequisite: batdrv_init(), batdrv_select_battery() local new_start=${1:-} local new_stop=${2:-} local verb=${3:-0} local old_start old_stop # insert defaults [ "$new_start" = "DEF" ] && new_start=$_bt_def_start [ "$new_stop" = "DEF" ] && new_stop=$_bt_def_stop # --- validate thresholds local rc if [ -n "$4" ] && [ -z "$new_start" ] && [ -z "$new_stop" ]; then # do nothing if unconfigured echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).not_configured: bat=$_bat_str; cfg=$_bt_cfg_bat" return 1 fi # start: check for 3 digits max, ensure min 0 / max 99 if ! is_uint "$new_start" 3 || \ ! is_within_bounds "$new_start" 0 99; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_start: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at START_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_start}\": not specified, invalid or out of range (0..99). Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at START_CHARGE_THRESH_%s=\"%s\": not specified, invalid or out of range (0..99). Aborted.\n" "$_bt_cfg_bat" "$new_start" 1>&2 else printf "Error: start charge threshold (%s) for %s is not specified, invalid or out of range (0..99). Aborted.\n" "$new_start" "$_bat_str" 1>&2 fi ;; esac return 2 fi # stop: check for 3 digits max, ensure min 1 / max 100 if ! is_uint "$new_stop" 3 || \ ! is_within_bounds "$new_stop" 1 100; then # threshold out of range echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_stop: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration at STOP_CHARGE_THRESH_${_bt_cfg_bat}=\"${new_stop}\": not specified, invalid or out of range (1..100). Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration at STOP_CHARGE_THRESH_%s=\"%s\": not specified, invalid or out of range (1..100). Aborted.\n" "$_bt_cfg_bat" "$new_stop" 1>&2 else printf "Error: stop charge threshold (%s) for %s is not specified, invalid or out of range (1..100). Aborted.\n" "$new_stop" "$_bat_str" 1>&2 fi ;; esac return 2 fi # check start < stop if [ "$new_start" -ge "$new_stop" ]; then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).invalid_diff: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) if [ -n "$4" ]; then echo_message "Error in configuration: START_CHARGE_THRESH_${_bt_cfg_bat} >= STOP_CHARGE_THRESH_${_bt_cfg_bat}. Battery skipped." fi ;; 2) if [ -n "$4" ]; then printf "Error in configuration: START_CHARGE_THRESH_%s >= STOP_CHARGE_THRESH_%s. Aborted.\n" "$_bt_cfg_bat" "$_bt_cfg_bat" 1>&2 else printf "Error: start threshold >= stop threshold for %s. Aborted.\n" "$_bat_str" 1>&2 fi ;; esac return 3 fi # read active threshold values if ! old_start=$(batdrv_read_threshold start 0) || \ ! old_stop=$(batdrv_read_threshold stop 0); then echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).read_error: bat=$_bat_str; cfg=$_bt_cfg_bat" case $verb in 1) echo_message "Error: could not read current charge threshold(s) for $_bat_str. Battery skipped." ;; 2) printf "Error: could not read current charge threshold(s) for %s. Aborted.\n" "$_bat_str" 1>&2 ;; esac return 4 fi # determine write sequence too meet boundary condition start < stop # disclaimer: the driver doesn't enforce it but we don't know about the # firmware and it's reasonable anyway local rc=0 steprc tseq if [ "$new_start" -ge "$old_stop" ]; then tseq="stop start" else tseq="start stop" fi # write new thresholds in determined sequence if [ "$verb" = "2" ]; then printf "Setting temporary charge thresholds for %s:\n" "$_bat_str" fi for step in $tseq; do local old_thresh new_thresh steprc case $step in start) old_thresh=$old_start new_thresh=$new_start ;; stop) old_thresh=$old_stop new_thresh=$new_stop ;; esac if [ "$old_thresh" != "$new_thresh" ]; then # new threshold differs from effective one --> write it case $step in start) write_sysf "$new_thresh" "$_bf_start" ;; stop) write_sysf "$new_thresh" "$_bf_stop" ;; esac steprc=$?; [ $steprc -ne 0 ] && rc=5 echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).$step.write: bat=$_bat_str; cfg=$_bt_cfg_bat; old=$old_thresh; new=$new_thresh; steprc=$steprc" case $verb in 2) if [ $steprc -eq 0 ]; then printf " %-5s = %3d\n" "$step" "$new_thresh" else printf " %-5s = %3d (Error: write failed)\n" "$step" "$new_thresh" 1>&2 fi ;; 1) if [ $steprc -gt 0 ]; then echo_message "Error: writing $step charge threshold for $_bat_str failed." fi ;; esac else echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).$step.no_change: bat=$_bat_str; old=$old_thresh; new=$new_thresh" if [ "$verb" = "2" ]; then printf " %-5s = %3d (no change)\n" "$step" "$new_thresh" fi fi done # for step echo_debug "bat" "batdrv.${_batdrv_plugin}.write_thresholds($1, $2, $3, $4).complete: bat=$_bat_str; cfg=$_bt_cfg_bat; rc=$rc" return $rc } batdrv_chargeonce () { # function not implemented echo_debug "bat" "batdrv.${_batdrv_plugin}.charge_once.not_implemented" return 255 } batdrv_apply_configured_thresholds () { # apply configured stop thresholds from configuration to all batteries # - called for bg tasks tlp init [re]start/auto and tlp start # output parameter errors only # prerequisite: batdrv_init() local start_thresh stop_thresh if batdrv_select_battery "DEF"; then eval start_thresh="\$START_CHARGE_THRESH_${_bt_cfg_bat}" eval stop_thresh="\$STOP_CHARGE_THRESH_${_bt_cfg_bat}" batdrv_write_thresholds "$start_thresh" "$stop_thresh" 1 1 fi return 0 } batdrv_read_force_discharge () { # function not implemented for System76 laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.read_force_discharge.not_implemented" return 255 } batdrv_write_force_discharge () { # function not implemented for System76 laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.write_force_discharge.not_implemented" return 255 } batdrv_cancel_force_discharge () { # function not implemented for System76 laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.cancel_force_discharge.not_implemented" return 255 } batdrv_force_discharge_active () { # function not implemented for System76 laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() echo_debug "bat" "batdrv.${_batdrv_plugin}.force_discharge_active.not_implemented" return 255 } batdrv_discharge () { # function not implemented for System76 laptops # global param: $_batdrv_plugin # prerequisite: batdrv_init() # Important: release lock from caller unlock_tlp tlp_discharge echo_debug "bat" "batdrv.${_batdrv_plugin}.discharge.not_implemented" return 255 } batdrv_show_battery_data () { # output battery status # $1: 1=verbose # global params: $_batdrv_plugin, $_batteries, $_batdrv_kmod, $_bd_read, $_bf_start, $_bf_stop, $_bf_dischg # prerequisite: batdrv_init() local verbose=${1:-0} printf "+++ Battery Care\n" printf "Plugin: %s\n" "$_batdrv_plugin" if [ "$_bm_thresh" != "none" ]; then printf "Supported features: charge thresholds\n" else printf "Supported features: none available\n" fi printf "Driver usage:\n" # native kernel ACPI battery API case $_natacpi in 0) printf "* natacpi (%s) = active (charge thresholds)\n" "$_batdrv_kmod" ;; 32) printf "* natacpi (%s) = inactive (disabled by configuration)\n" "$_batdrv_kmod" ;; 128) printf "* natacpi (%s) = inactive (no kernel support)\n" "$_batdrv_kmod" ;; 254) printf "* natacpi (%s) = inactive (laptop not supported)\n" "$_batdrv_kmod" ;; *) printf "* natacpi (%s) = unknown status\n" "$_batdrv_kmod" ;; esac if [ "$_bm_thresh" != "none" ]; then printf "Parameter value ranges:\n" printf "* START_CHARGE_THRESH_BAT0: 0(off)..90(default)..99\n" printf "* STOP_CHARGE_THRESH_BAT0: 1..100(default)\n" fi printf "\n" # -- show battery data local bat local bcnt=0 local ed ef en local efsum=0 local ensum=0 for bat in $_batteries; do # iterate batteries batdrv_select_battery "$bat" printf "+++ Battery Status: %s\n" "$bat" printparm "%-59s = ##%s##" "$_bd_read/manufacturer" printparm "%-59s = ##%s##" "$_bd_read/model_name" print_battery_cycle_count "$_bd_read/cycle_count" "$(read_sysf "$_bd_read/cycle_count")" if [ -f "$_bd_read/energy_full" ]; then printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full_design" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_full" "" 000 printparm "%-59s = ##%6d## [mWh]" "$_bd_read/energy_now" "" 000 printparm "%-59s = ##%6d## [mW]" "$_bd_read/power_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/energy_full_design") ef=$(read_sysval "$_bd_read/energy_full") en=$(read_sysval "$_bd_read/energy_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) elif [ -f "$_bd_read/charge_full" ]; then printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full_design" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_full" "" 000 printparm "%-59s = ##%6d## [mAh]" "$_bd_read/charge_now" "" 000 printparm "%-59s = ##%6d## [mA]" "$_bd_read/current_now" "" 000 # store values for charge / capacity calculation below ed=$(read_sysval "$_bd_read/charge_full_design") ef=$(read_sysval "$_bd_read/charge_full") en=$(read_sysval "$_bd_read/charge_now") efsum=$((efsum + ef)) ensum=$((ensum + en)) else ed=0 ef=0 en=0 fi print_batstate "$_bd_read/status" printf "\n" if [ "$verbose" -eq 1 ]; then printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_min_design" "" 000 printparm "%-59s = ##%6s## [mV]" "$_bd_read/voltage_now" "" 000 printf "\n" fi # --- show battery features: thresholds if [ "$_bm_thresh" = "natacpi" ]; then printf "%-59s = %6s [%%]\n" "$_bf_start" "$(batdrv_read_threshold start 1)" printf "%-59s = %6s [%%]\n" "$_bf_stop" "$(batdrv_read_threshold stop 1)" printf "\n" fi # --- show charge level (SOC) and capacity lf=0 if [ "$ef" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Charge", 100.0 * '"$en"' / '"$ef"');' lf=1 fi if [ "$ed" -ne 0 ]; then perl -e 'printf ("%-59s = %6.1f [%%]\n", "Capacity", 100.0 * '"$ef"' / '"$ed"');' lf=1 fi [ "$lf" -gt 0 ] && printf "\n" bcnt=$((bcnt+1)) done # for bat return 0 } batdrv_recommendations () { # no recommendations return 0 } ukui-power-manager/3rd/tlp/defaults.conf0000664000175000017500000000305415167661430017177 0ustar fengfeng# /usr/share/tlp/defaults.conf - TLP intrinsic defaults # IMPORTANT: do not edit this file, put your settings in /etc/tlp.conf or # /etc/tlp.d/*.conf instead! # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later TLP_ENABLE=1 TLP_WARN_LEVEL=3 TLP_PERSISTENT_DEFAULT=0 DISK_IDLE_SECS_ON_AC=0 DISK_IDLE_SECS_ON_BAT=2 MAX_LOST_WORK_SECS_ON_AC=15 MAX_LOST_WORK_SECS_ON_BAT=60 CPU_ENERGY_PERF_POLICY_ON_AC=balance_performance CPU_ENERGY_PERF_POLICY_ON_BAT=balance_power NMI_WATCHDOG=0 DISK_DEVICES="nvme0n1 sda" DISK_APM_LEVEL_ON_AC="254 254" DISK_APM_LEVEL_ON_BAT="128 128" DISK_APM_CLASS_DENYLIST="usb ieee1394" DISK_IOSCHED="keep keep" SATA_LINKPWR_ON_AC="med_power_with_dipm" SATA_LINKPWR_ON_BAT="med_power_with_dipm" AHCI_RUNTIME_PM_ON_AC=on AHCI_RUNTIME_PM_ON_BAT=auto AHCI_RUNTIME_PM_TIMEOUT=15 PCIE_ASPM_ON_AC=default PCIE_ASPM_ON_BAT=default RADEON_DPM_PERF_LEVEL_ON_AC=auto RADEON_DPM_PERF_LEVEL_ON_BAT=auto RADEON_POWER_PROFILE_ON_AC=default RADEON_POWER_PROFILE_ON_BAT=default WIFI_PWR_ON_AC=off WIFI_PWR_ON_BAT=on WOL_DISABLE=Y SOUND_POWER_SAVE_ON_AC=1 SOUND_POWER_SAVE_ON_BAT=1 SOUND_POWER_SAVE_CONTROLLER=Y BAY_POWEROFF_ON_AC=0 BAY_POWEROFF_ON_BAT=0 BAY_DEVICE="sr0" RUNTIME_PM_ON_AC=on RUNTIME_PM_ON_BAT=auto RUNTIME_PM_DRIVER_DENYLIST="mei_me nouveau radeon xhci_hcd" USB_AUTOSUSPEND=1 USB_EXCLUDE_AUDIO=1 USB_EXCLUDE_BTUSB=0 USB_EXCLUDE_PHONE=0 USB_EXCLUDE_PRINTER=1 USB_EXCLUDE_WWAN=0 RESTORE_DEVICE_STATE_ON_STARTUP=0 RESTORE_THRESHOLDS_ON_BAT=0 NATACPI_ENABLE=1 TPACPI_ENABLE=1 TPSMAPI_ENABLE=1 ukui-power-manager/3rd/tlp/tlp-func-base0000664000175000017500000007550715167661430017120 0ustar fengfeng#!/bin/sh # tlp - Base Functions # # Copyright (c) 2024 Thomas Koch and others. # SPDX-License-Identifier: GPL-2.0-or-later # shellcheck disable=SC2034 # ---------------------------------------------------------------------------- # Constants readonly TLPVER="1.7.0-alpha.0" readonly RUNDIR=/run/tlp readonly VARDIR=/var/lib/tlp readonly CONF_DEF=/usr/share/ukui-power-manager/tlp/defaults.conf readonly CONF_DIR=/usr/share/ukui-power-manager/tlp/tlp.d readonly CONF_USR=/usr/share/ukui-power-manager/tlp/tlp.conf readonly CONF_OLD=/etc/default/tlp readonly CONF_RUN="$RUNDIR/run.conf" readonly FLOCK=flock readonly HDPARM=hdparm readonly LAPMODE=laptop_mode readonly LOGGER=logger readonly MKTEMP=mktemp readonly MODPRO=modprobe readonly READCONFS=/usr/share/ukui-power-manager/tlp/tlp-readconfs readonly SYSTEMCTL=systemctl readonly TPACPIBAT=/usr/share/ukui-power-manager/tlp/tpacpi-bat readonly UDEVADM=udevadm readonly TLPRDW=tlp-rdw readonly LOCKFILE=$RUNDIR/lock readonly LOCKTIMEOUT=2 readonly PWRRUNFILE=$RUNDIR/last_pwr readonly MANUALMODEFILE=$RUNDIR/manual_mode readonly MOD_MSR="msr" readonly MOD_TEMP="coretemp" readonly DMID=/sys/class/dmi/id/ readonly NETD=/sys/class/net readonly TPACPID=/sys/devices/platform/thinkpad_acpi readonly RE_PARAM='^[A-Z_]+[0-9]*=[-0-9a-zA-Z _.:]*$' # power supplies: ignore MacBook Pro 2017 sbs-charger and hid devices readonly RE_PS_IGNORE='sbs-charger|hidpp_battery|hid-' readonly DEBUG_TAGS_ALL="arg bat cfg disk lock nm path pm ps rf run sysfs udev usb" readonly TLP_SERVICES="tlp.service" readonly PPD_SERVICE="power-profiles-daemon.service" readonly RFKILL_SERVICES="systemd-rfkill.service systemd-rfkill.socket" # ---------------------------------------------------------------------------- # Control _nodebug=0 # ---------------------------------------------------------------------------- # Functions # -- Exit do_exit () { # cleanup and exit -- $1: rc # remove temporary runconf [ -z "$_conf_tmp" ] || rm -f -- "$_conf_tmp" exit "$1" } # --- Messages echo_debug () { # write debug msg if tag matches -- $1: tag; $2: msg; [ "$_nodebug" = "1" ] && return 0 if wordinlist "$1" "$TLP_DEBUG"; then $LOGGER -p debug -t "tlp" --id=$$ -- "$2" > /dev/null 2>&1 fi } echo_message () { # output message according to TLP_MSG_LEVEL # $1: message # $2: loglevel for syslog (default: warning) # shellcheck disable=SC2154 if [ "$_bgtask" = "1" ]; then # called from background task --> use syslog if [ -n "$1" ]; then case "$TLP_WARN_LEVEL" in 1|3) $LOGGER -p "${2:-warning}" -t "tlp" --id=$$ -- "$1" > /dev/null 2>&1 ;; esac fi else # called from command line task --> use stderr case "$TLP_WARN_LEVEL" in 2|3) # shellcheck disable=SC2059 printf "$1\n" 1>&2 ;; esac fi } print_version () { echo "TLP version $TLPVER" } # --- Strings tolower () { # print string in lowercase -- $1: string printf "%s" "$1" | tr "[:upper:]" "[:lower:]" } toupper () { # print string in uppercase -- $1: string printf "%s" "$1" | tr "[:lower:]" "[:upper:]" } wordinlist () { # test if word in list # $1: word, $2: whitespace-separated list of words local word if [ -n "${1-}" ]; then for word in ${2-}; do [ "${word}" != "${1}" ] || return 0 # exact match done fi return 1 # no match } # --- Sysfiles read_sysf () { # read and print contents of a sysfile # return 1 and print default if read fails # $1: sysfile # $2: default # rc: 0=ok/1=error if cat "$1" 2> /dev/null; then # echo "$1" ":" `cat "$1" 2> /dev/null`>> /usr/share/ukui-power-manager/tlp/origin_tmp.conf return 0 else printf "%s" "$2" return 1 fi } readable_sysf () { # check if sysfile is actually readable # $1: file # rc: 0=readable/1=read error cat "$1" > /dev/null 2>&1 } read_sysval () { # read and print contents of a sysfile # print '0' if file is non-existent, read fails or content is non-numeric # $1: sysfile # rc: 0=ok/1=error printf "%d" "$(read_sysf "$1")" 2> /dev/null } write_sysf () { # write string to a sysfile # $1: string # $2: sysfile # rc: 0=ok/1=error case "$UPM_TLP_FLAG" in ONLY_ECHO_PATH) echo "$2" >> /usr/share/ukui-power-manager/tlp/origin_tmp.conf ;; *) { printf '%s\n' "$1" > "$2"; } 2> /dev/null ;; esac } # --- Globbing glob_files () { # @stdout glob_files ( glob_pattern, dir[, dir...] ) # # Nested loop that applies a glob expression to several directories # (or path prefixes) and prints matching file paths (including symlinks) # to stdout. # # NOTE: for x in $(glob_files 'a*' dirpath ); do ...; done # globs twice: # (a) once in the "for file_iter" loop in glob_files() # (b) another time when x gets word expanded in the "for x" loop # crafted filenames (e.g. a file named '*') will break this function, # as such it should be only be used with 'sort-of trustworthy' directories # (sysfs, proc). [ -n "${1-}" ] || return 64 local glob_pattern file_iter local rc=1 glob_pattern="${1}" while shift && [ $# -gt 0 ]; do for file_iter in ${1}${glob_pattern}; do if [ -f "${file_iter}" ] || [ -L "${file_iter}" ]; then printf '%s\n' "${file_iter}" rc=0 fi done done return $rc } glob_dirs () { # @stdout glob_dirs ( glob_pattern, dir[, dir...] ) # # Nested loop that applies a glob expression to several directories # (or path prefixes) and prints matching directory paths to stdout. # # NOTE: globs twice, see glob_files(). [ -n "${1-}" ] || return 64 local glob_pattern dir_iter local rc=1 glob_pattern="${1}" while shift && [ $# -gt 0 ]; do for dir_iter in ${1}${glob_pattern}; do if [ -d "${dir_iter}" ]; then printf '%s\n' "${dir_iter}" rc=0 fi done done return $rc } # --- Checks cmd_exists () { # test if command exists -- $1: command command -v "$1" > /dev/null 2>&1 } test_root () { # test root privilege -- rc: 0=root, 1=not root [ "$(id -u)" = "0" ] } check_root () { # show error message and quit when root privilege missing if ! test_root; then echo "Error: missing root privilege." 1>&2 do_exit 1 fi } check_tlp_enabled () { # check if TLP is enabled in config file # $1: 1=verbose (default: 0) # rc: 0=disabled/1=enabled if [ "$TLP_ENABLE" = "1" ]; then return 0 else [ "${1:-0}" = "1" ] && echo "Error: TLP power save is disabled. Set TLP_ENABLE=1 in ${CONF_USR}." 1>&2 return 1 fi } check_rdw_installed () { cmd_exists "$TLPRDW" } check_systemd () { # check if systemd is the active init system (PID 1) and systemctl is installed # rc: 0=yes, 1=no [ -d /run/systemd/system ] && cmd_exists $SYSTEMCTL } check_service_state () { # check service state # $1: service # $2: state match: active/enabled/masked # rc: 0=yes, 1=no case "$2" in active) $SYSTEMCTL is-active "$1" > /dev/null 2>&1 ;; enabled) $SYSTEMCTL is-enabled "$1" > /dev/null 2>&1 ;; masked) $SYSTEMCTL is-enabled "$1" 2> /dev/null | grep -q 'masked' ;; esac } check_ppd_active () { # check if power-profiles-daemon.service is running # rc: 0=yes, 1=no check_service_state "$PPD_SERVICE" active } check_services_activation_status () { # issue messages for # - TLP service(s) not enabled # - conflicting services enabled # rc: 0=no messages/messages issued local rc=0 if check_systemd; then cnt=0 for su in $TLP_SERVICES; do if ! check_service_state "$su" enabled > /dev/null 2>&1 ; then echo_message "Error: TLP's power saving will not apply on boot because $su is not enabled "` `"--> Invoke 'systemctl enable $su' to ensure the full functionality of TLP." "err" echo_message "" rc=1 fi done for su in $RFKILL_SERVICES; do if ! check_service_state "$su" masked 2> /dev/null; then if [ "$RESTORE_DEVICE_STATE_ON_STARTUP" = "1" ]; then echo_message "Warning: TLP's radio device switching on boot may not work as expected because "` `"RESTORE_DEVICE_STATE_ON_STARTUP=1 is configured and $su is not masked "` `"--> Invoke 'systemctl mask $su' to ensure the full functionality of TLP." "err" echo_message "" elif [ -n "$DEVICES_TO_DISABLE_ON_STARTUP" ] || [ -n "$DEVICES_TO_ENABLE_ON_STARTUP" ]; then echo_message "Warning: TLP's radio device switching on boot may not work as expected because "` `"DEVICES_TO_DISABLE_ON_STARTUP or DEVICES_TO_ENABLE_ON_STARTUP "` `"is configured and $su is not masked "` `"--> Invoke 'systemctl mask $su' to ensure the full functionality of TLP." "err" echo_message "" fi rc=1 fi done fi return $rc } # --- Type and value checking is_uint () { # check for unsigned integer -- $1: string; $2: max digits printf "%s" "$1" | grep -E -q "^[0-9]{1,$2}$" 2> /dev/null } is_within_bounds () { # check condition min <= value <= max # $1: value; $2: min; $3: max (all unsigned int) # rc: 0=within/1=below/2=above/255=invalid # # value, min or max undefined/non-numeric means that this branch of the # condition is fulfilled is_uint "$1" || return 255 if is_uint "$2"; then [ "$1" -ge "$2" ] || return 1 fi if is_uint "$3"; then [ "$1" -le "$3" ] || return 2 fi return 0 } # --- Locking and Semaphores set_run_flag () { # set flag -- $1: flag name # rc: 0=success/1,2=failed local rc create_rundir touch "$RUNDIR/$1"; rc=$? echo_debug "lock" "set_run_flag.touch: $1; rc=$rc" return $rc } reset_run_flag () { # reset flag -- $1: flag name if rm "$RUNDIR/$1" 2> /dev/null 1>&2 ; then echo_debug "lock" "reset_run_flag($1).remove" else echo_debug "lock" "reset_run_flag($1).not_found" fi return 0 } check_run_flag () { # check flag -- $1: flag name # rc: 0=flag set/1=flag not set local rc [ -f "$RUNDIR/$1" ]; rc=$? echo_debug "lock" "check_run_flag($1): rc=$rc" return $rc } lock_tlp () { # get exclusive lock: blocking with timeout # $1: lock id (default: tlp) # rc: 0=success/1=failed create_rundir # open file for writing and attach fd 9 # when successful lock fd 9 exclusive and blocking # wait $LOCKTIMEOUT secs to obtain the lock if { exec 9> "${LOCKFILE}_${1:-tlp}" ; } 2> /dev/null && $FLOCK -x -w $LOCKTIMEOUT 9 ; then echo_debug "lock" "lock_tlp($1).success" return 0 else echo_debug "lock" "lock_tlp($1).failed" return 1 fi } lock_tlp_nb () { # get exclusive lock: non-blocking # $1: lock id (default: tlp) # rc: 0=success/1=failed create_rundir # open file for writing and attach fd 9 # when successful lock fd 9 exclusive and non-blocking if { exec 9> "${LOCKFILE}_${1:-tlp}" ; } 2> /dev/null && $FLOCK -x -n 9 ; then echo_debug "lock" "lock_tlp_nb($1).success" return 0 else echo_debug "lock" "lock_tlp_nb($1).failed" return 1 fi } unlock_tlp () { # free exclusive lock # $1: lock id (default: tlp) # defer unlock for $X_DEFER_UNLOCK seconds -- debugging only [ -n "$X_DEFER_UNLOCK" ] && sleep "$X_DEFER_UNLOCK" # free fd 9 and scrap lockfile { exec 9>&- ; } 2> /dev/null rm -f "${LOCKFILE}_${1:-tlp}" echo_debug "lock" "unlock_tlp($1)" return 0 } lockpeek_tlp () { # check for pending lock (by looking for the lockfile) # $1: lock id (default: tlp) if [ -f "${LOCKFILE}_${1:-tlp}" ]; then echo_debug "lock" "lockpeek_tlp($1).locked" return 0 else echo_debug "lock" "lockpeek_tlp($1).not_locked" return 1 fi } echo_tlp_locked () { # print "locked" message echo "Error: TLP is locked by another operation." 1>&2 return 0 } set_timed_lock () { # create timestamp n seconds in the future # $1: lock id, $2: lock duration [s] local lock rc time lock="${1}_timed_lock_$(date +%s -d "+${2} seconds")" set_run_flag "$lock"; rc=$? echo_debug "lock" "set_timed_lock($1, $2): $lock; rc=$rc" # cleanup obsolete locks time=$(date +%s) for lockfile in "$RUNDIR/${1}_timed_lock_"*; do if [ -f "$lockfile" ]; then locktime="${lockfile#"${RUNDIR}/${1}_timed_lock_"}" if [ "$time" -ge "$locktime" ]; then rm -f "$lockfile" echo_debug "lock" "set_timed_lock($1, $2).remove_obsolete: ${lockfile#"${RUNDIR}/"}" fi fi done return $rc } check_timed_lock () { # check if active timestamp exists # $1: lock id; rc: 0=locked/1=not locked local lockfile locktime time time=$(date +%s) for lockfile in "$RUNDIR/${1}_timed_lock_"*; do if [ -f "$lockfile" ]; then locktime=${lockfile#"${RUNDIR}/${1}_timed_lock_"} if [ "$time" -lt $(( locktime - 120 )) ]; then # timestamp is more than 120 secs in the future, # something weird has happened -> remove it rm -f "$lockfile" echo_debug "lock" "check_timed_lock($1).remove_invalid: ${lockfile#"${RUNDIR}/"}" elif [ "$time" -lt "$locktime" ]; then # timestamp in the future -> we're locked echo_debug "lock" "check_timed_lock($1).locked: $time, $locktime" return 0 else # obsolete timestamp -> remove it rm -f "$lockfile" echo_debug "lock" "check_timed_lock($1).remove_obsolete: ${lockfile#"${RUNDIR}/"}" fi fi done echo_debug "lock" "check_timed_lock($1).not_locked: $time" return 1 } # --- Environment print_shell () { # determine the shell executing this script readlink -n "/proc/$$/exe" } add_sbin2path () { # check if /sbin /usr/sbin in $PATH, otherwise add them # retval: $PATH, $_oldpath, $_addpath local sp _oldpath="$PATH" _addpath="" for sp in /usr/sbin /sbin; do if [ -d $sp ] && [ ! -h $sp ]; then # dir exists and is not a symlink case ":$PATH:" in *":$sp:"*) # $sp already in $PATH ;; *) # $sp not in $PATH, add it _addpath="$_addpath:$sp" ;; esac fi done if [ -n "$_addpath" ]; then export PATH="${PATH}${_addpath}" fi return 0 } # --- Directories and Files create_rundir () { # make sure $RUNDIR exists [ -d $RUNDIR ] || mkdir -p $RUNDIR 2> /dev/null 1>&2 } chmod_readable4all () { # make file world readable -- $1: file chmod -f o+r "$1" } # -- Battery Plugins select_batdrv () { # source battery feature drivers and # activate the one that matches the hardware # do not execute twice # shellcheck disable=SC2154 [ -z "$_batdrv_selected" ] || return 0 # iterate until a matching driver is found for batdrv in /usr/share/ukui-power-manager/tlp/bat.d/[0-9][0-9]-[a-z]*; do # shellcheck disable=SC1090 . "$batdrv" || exit 70 # end iteration when a matching driver is found batdrv_init && break done return 0 } # --- Configuration read_config () { # read all config files and write temporary runconf file # $1: 0=continue/1=quit on error # $2: 1=no trace # rc: 0=ok/5=tlp.conf missing/6=defaults.conf missing/7=file creation error # retval: config parameters; # _conf_tmp: runconf local rc=0 local tmpdir if test_root; then tmpdir=$RUNDIR create_rundir else tmpdir=${TMPDIR:-/tmp} fi if _conf_tmp=$($MKTEMP -p "$tmpdir" "tlp-run.conf_tmpXXXXXX"); then # external perl script: merge all config files to $cf if [ "$2" = "1" ]; then $READCONFS --outfile "$_conf_tmp" --notrace; rc=$? else $READCONFS --outfile "$_conf_tmp"; rc=$? fi # shellcheck disable=SC1090 [ $rc -eq 0 ] && . "$_conf_tmp" else rc=7 fi if [ $rc -ne 0 ]; then case $rc in 5) echo "Error: cannot read user configuration from $CONF_USR or $CONF_OLD." 1>&2 ;; 6) echo "Error: cannot read default configuration from $CONF_DEF." 1>&2 ;; 7) echo "Error: cannot write runtime configuration to $_conf_tmp." 1>&2 ;; esac if [ "$1" = "1" ]; then do_exit $rc fi fi return 0 } parse_args4config () { # parse command-line arguments: everything after the # delimiter '--' is interpreted as a config parameter # retval: config parameters local argd="" cfgd="" dflag=0 param value # iterate arguments while [ $# -gt 0 ]; do if [ $dflag -eq 1 ]; then # delimiter was passed --> sanitize and parse argument: # quotes stripped by the shell calling tlp # format is PARAMETER=value # PARAMETER allows 'A'..'Z' and '_' only, may end in a number (_BAT0) # value allows 'A'..'Z', 'a'..'z', '0'..'9', ' ', '-', '_', '.', ':' # value may be an empty string if printf "%s" "$1" | grep -E -q "$RE_PARAM"; then param="${1%%=*}" value="${1#*=}" if [ -n "$param" ]; then eval "$param='$value'" 2> /dev/null cfgd="$cfgd $param=""$value""" fi fi elif [ "$1" = "--" ]; then # delimiter reached --> begin interpretation dflag=1 else argd="$argd $1" fi shift # next argument done # while arguments echo_debug "arg" "parse_args4config: ${0##/*/}$argd --$cfgd" return 0 } save_runconf () { # copy temporary to final runconf create_rundir if cp --preserve=timestamps "$_conf_tmp" $CONF_RUN > /dev/null 2>&1; then chmod 664 "$_conf_tmp" $CONF_RUN > /dev/null 2>&1 echo_debug "run" "save_runconf.ok: $_conf_tmp -> $CONF_RUN" else echo_debug "run" "save_runconf.failed: $_conf_tmp -> $CONF_RUN" fi } # --- Kernel kernel_version_ge () { # check if running kernel version >= $1: minimum version [ "$1" = "$(printf "%s\n%s\n" "$1" "$(uname -r)" | sort -V | head -n 1)" ] } load_modules () { # load kernel module(s) -- $*: modules local mod # verify module loading is allowed (else explicitly disabled) # and possible (else implicitly disabled) [ "${TLP_LOAD_MODULES:-y}" = "y" ] && [ -e /proc/modules ] || return 0 # load modules, ignore any errors # shellcheck disable=SC2048 for mod in $*; do $MODPRO "$mod" > /dev/null 2>&1 done return 0 } # --- DMI read_dmi () { # read DMI data # $1: dmi id # stdout: dmi string # rc: 0=ok/1=nonexistent local out out="$(read_sysf "${DMID}/$1" | \ grep -E -v -i 'not available|to be filled|DMI table is broken')" printf '%s' "$out" if [ -n "$out" ]; then return 0 else return 1 fi } # --- Power Source get_sys_power_supply () { # determine active power supply # $1: command # rc: 0=ac/1=battery/2=unknown # retval: $_syspwr == rc # $_psdev: 1st power supply found (for udev rule check) # # examine all power supply devices in lexical order, typically this is: # AC, ADPx (AC chargers) -> BATx, CMBx (batteries) -> ucsi* (USB). # names in $RE_PS_IGNORE are ignored. # # the ranking of power source classes for the determination of the active # power supply is as follows: # 1. AC chargers # 2. Batteries # 3. USB # $TLP_PS_IGNORE may be used to ignore one or more power source classes local bs ps_ignore psrc psrc_name local ac0seen= local wait= _psdev="" _syspwr="$X_SIMULATE_PS" if [ -n "$_syspwr" ]; then # simulate power supply echo_debug "ps" "get_sys_power_supply.simulate: syspwr=$_syspwr" return "$_syspwr" fi ps_ignore=$(toupper "$TLP_PS_IGNORE") for psrc in /sys/class/power_supply/*; do # -f $psrc/type not necessary - read_sysf() handles this psrc_name="${psrc##*/}" # ignore atypical power supplies and batteries printf '%s\n' "$psrc_name" | grep -E -q "$RE_PS_IGNORE" && continue case "$(read_sysf "$psrc/type")" in Mains) # AC detected _psdev="${_psdev:-$psrc}" # if configured, skip device to ignore incorrect AC status if wordinlist "AC" "$ps_ignore"; then echo_debug "ps" "get_sys_power_supply(${psrc_name}).ac_ignored: syspwr=$_syspwr" continue fi # check AC status if [ "$(read_sysf "$psrc/online")" = "1" ]; then # AC online --> end iteration _syspwr=0 echo_debug "ps" "get_sys_power_supply(${psrc_name}).ac_online: syspwr=$_syspwr" break else # AC offine --> end iteration _syspwr=1 echo_debug "ps" "get_sys_power_supply(${psrc_name}).ac_offline: syspwr=$_syspwr" break fi ;; USB) # USB PS detected _psdev="${_psdev:-$psrc}" # if configured, skip device to ignore incorrect AC status if wordinlist "USB" "$ps_ignore"; then echo_debug "ps" "get_sys_power_supply(${psrc_name}).usb_ignored: syspwr=$_syspwr" continue fi # check USB PS status if [ "$(read_sysf "$psrc/online")" = "1" ]; then # USB online --> end iteration _syspwr=0 echo_debug "ps" "get_sys_power_supply(${psrc_name}).usb_online: syspwr=$_syspwr" break else # USB PS offline could mean battery, but multiple connectors may exist # --> remember and continue looking ac0seen=1 echo_debug "ps" "get_sys_power_supply(${psrc_name}).remember_usb_offline" fi ;; Battery) # battery detected _psdev="${_psdev:-$psrc}" # if configured, skip device to ignore incorrect battery status if wordinlist "BAT" "$ps_ignore"; then echo_debug "ps" "get_sys_power_supply(${psrc_name}).bat_ignored: syspwr=$_syspwr" continue fi # check battery status bs="$(read_sysf "$psrc/status")" if [ "$bs" != "Discharging" ] && [ "$1" = "auto" ] && [ -z "$wait" ]; then # when command is 'tlp auto', not "Discharging" might be caused by lagging battery status updates # --> recheck every 0.1 secs for 1.5 secs (or user value in deciseconds) max # use delay loop only once wait="$X_PS_WAIT_DS" is_uint "$wait" 2 || wait=15 echo_debug "ps" "get_sys_power_supply(${psrc_name}).bat_not_discharging_recheck: bs=$bs; syspwr=$_syspwr; wait=$wait" while [ "$wait" -gt 0 ]; do sleep 0.1 wait=$((wait - 1)) bs="$(read_sysf "$psrc/status")" [ "$bs" = "Discharging" ] && break done fi case "$bs" in Discharging) if ! lockpeek_tlp tlp_discharge; then # battery status "Discharging" means battery mode ... _syspwr=1 echo_debug "ps" "get_sys_power_supply(${psrc_name}).bat_discharging: syspwr=$_syspwr; wait=$wait" else # ... unless forced discharge is in progress, which means AC _syspwr=0 echo_debug "ps" "get_sys_power_supply(${psrc_name}).forced_discharge: syspwr=$_syspwr; wait=$wait" fi break # --> end iteration ;; *) # assume AC mode for everything else, e.g. "Charging", "Full", "Not charging", "Unknown" # --> continue looking because there may be multiple batteries _syspwr=0 echo_debug "ps" "get_sys_power_supply(${psrc_name}).bat_not_discharging: bs=$bs; syspwr=$_syspwr; wait=$wait" ;; esac ;; *) # unknown power source type --> ignore ;; esac done if [ -z "$_syspwr" ]; then # _syspwr result yet undecided if [ "$ac0seen" = "1" ]; then # AC offline remembered --> battery mode _syspwr=1 echo_debug "ps" "get_sys_power_supply(${ac0seen##/*/}).ac_offline_remembered: syspwr=$_syspwr" else # we have seen neither a AC nor a battery power source --> unknown mode _syspwr=2 echo_debug "ps" "get_sys_power_supply.none_found: syspwr=$_syspwr" fi fi return "$_syspwr" } get_persist_mode () { # get persistent operation mode # rc: 0=persistent/1=not persistent # retval: $_persist_mode (0=ac, 1=battery, none) local rc=1 _persist_mode="none" if [ "$TLP_PERSISTENT_DEFAULT" = "1" ]; then # persistent mode = configured default mode case $(toupper "$TLP_DEFAULT_MODE") in AC) _persist_mode=0; rc=0 ;; BAT) _persist_mode=1; rc=0 ;; esac fi return $rc } get_power_mode () { # get current operation mode # $1: command # rc: 0=AC/1=battery # similar to get_sys_power_supply(), # but maps unknown power source to TLP_DEFAULT_MODE or returns # persistent mode when enabled get_sys_power_supply "$1" local rc=$? if get_persist_mode; then # persistent mode rc=$_persist_mode else # non-persistent mode, use current power source if [ $rc -eq 2 ]; then # unknown power supply, use configured default mode case $(toupper "$TLP_DEFAULT_MODE") in AC) rc=0 ;; BAT) rc=1 ;; *) rc=0 ;; # use AC if none or invalid mode esac fi fi return $rc } compare_and_save_power_state() { # compare $1 to last saved power state, # save $1 afterwards when different # $1: new state 0=ac, 1=battery # rc: 0=different, 1=equal local lp # intercept invalid states case $1 in 0|1) ;; # valid state *) # invalid new state --> return "different" echo_debug "ps" "compare_and_save_power_state($1).invalid" return 0 ;; esac # read saved state lp=$(read_sysf $PWRRUNFILE) # compare if [ -z "$lp" ] || [ "$lp" != "$1" ]; then # saved state is nonexistent/empty or is different --> save new state create_rundir write_sysf "$1" $PWRRUNFILE echo_debug "ps" "compare_and_save_power_state($1).different: old=$lp" return 0 else # touch file for last run touch $PWRRUNFILE echo_debug "ps" "compare_and_save_power_state($1).equal" return 1 fi } clear_saved_power_state() { # remove last saved power state rm -f $PWRRUNFILE 2> /dev/null return 0 } check_ac_power () { # check if ac power connected -- $1: function if ! get_sys_power_supply ; then echo_debug "bat" "check_ac_power($1).no_ac_power" echo "Error: $1 is possible on AC power only." 1>&2 return 1 fi return 0 } echo_started_mode () { # print operation mode -- $1: 0=ac mode, 1=battery mode if [ "$1" = "0" ]; then printf "TLP started in AC mode" else printf "TLP started in battery mode" fi if [ "$_manual_mode" != "n" ]; then printf " (manual).\n" else printf " (auto).\n" fi return 0 } set_manual_mode () { # set manual operation mode # $1: 0=ac mode, 1=battery mode # retval: $_manual_mode (0=ac, 1=battery) if [ "$1" != "0" ] && [ "$1" != "1" ]; then echo_debug "pm" "set_manual_mode($1).invalid" return 1 fi create_rundir if write_sysf "$1" $MANUALMODEFILE; then _manual_mode="$1" echo_debug "pm" "set_manual_mode($1).ok" return 0 else echo_debug "pm" "set_manual_mode($1).write_error" return 1 fi } clear_manual_mode () { # remove manual operation mode # retval: $_manual_mode (none) rm -f $MANUALMODEFILE 2> /dev/null _manual_mode="n" echo_debug "pm" "clear_manual_mode" return 0 } get_manual_mode () { # get manual operation mode # rc: 0=active/1=inactive # retval: $_manual_mode (0=ac, 1=battery, a=active, n=inactive) local rc=1 _manual_mode="n" if [ -f $MANUALMODEFILE ]; then # read mode file if _manual_mode=$(read_sysf $MANUALMODEFILE); then case $_manual_mode in 0|1) rc=0 ;; *) _manual_mode="n" ;; esac else # cannot read mode file - possible cause: # tlp-stat -s is running without root privilege and the file is not world readable # because tlp ac/bat is invoked with sudo when creating the file and thereby a # restrictive umask applies; see https://github.com/linrunner/TLP/issues/702 # -> manual mode is active but operation mode cannot be determined _manual_mode="a" rc=0 fi fi return $rc } # --- Misc Checks check_laptop_mode_tools () { # check if lmt installed -- rc: 0=not installed, 1=installed if cmd_exists $LAPMODE; then echo 1>&2 echo "***Warning: laptop-mode-tools detected, this may cause conflicts with TLP." 1>&2 echo " Please uninstall laptop-mode-tools." 1>&2 echo 1>&2 echo_debug "pm" "check_laptop_mode_tools: yes" return 1 else return 0 fi } ukui-power-manager/plugin-power/0000775000175000017500000000000015167661430015660 5ustar fengfengukui-power-manager/plugin-power/translations/0000775000175000017500000000000015167661430020401 5ustar fengfengukui-power-manager/plugin-power/translations/ar.ts0000664000175000017500000003115515167661430021360 0ustar fengfeng Power Power قوة Require password when sleep/hibernate طلب كلمة المرور عند السكون / السبات Require password when sleep طلب كلمة المرور عند السكون Require password when hibernate طلب كلمة المرور عند السبات Password required when waking up the screen كلمة المرور مطلوبة عند إيقاظ الشاشة Press the power button اضغط على زر الطاقة Time to close display وقت إغلاق الشاشة Time to sleep وقت النوم Notebook cover غلاف دفتر الملاحظات Ice freeze mode وضع تجميد الجليد Using power استخدام الطاقة Using battery استخدام البطارية Automatically run ice freeze mode when low battery قم بتشغيل وضع تجميد الثلج تلقائيا عند انخفاض البطارية Battery level is lower than مستوى البطارية أقل من Run ركض Low battery notification إشعار انخفاض البطارية Automatically run saving mode when low battery تشغيل وضع التوفير تلقائيا عند انخفاض البطارية Display remaining charging time and usage time عرض وقت الشحن المتبقي ووقت الاستخدام General عام /Power/General Select power plan حدد خطة الطاقة /Power/Select power plan Battery saving plan خطة توفير البطارية /Power/Battery saving plan nothing شيء blank خلبي shutdown ايقاف التشغيل Fractional freezing التجميد الجزئي It can improve the smoothness of the system, and there may be stuttering after shutdown. يمكن أن يحسن نعومة النظام ، وقد يكون هناك تلعثم بعد الإغلاق. Open battery saving افتح توفير البطارية Auto display brightness level مستوى سطوع الشاشة التلقائي suspend تعليق hibernate السبات interactive تبادلي 5min 5 دقائق 10min 10 دقائق 15min 15 دقيقة 30min 30 دقيقة 1h 1 ساعة 2h 2 ساعة never أبدا 3h 3 ساعات Balance توازن Energy Efficiency كفاءة الطاقة Performance اداء It can improve battery life, but it will freeze background apps. يمكنه تحسين عمر البطارية ، لكنه سيجمد تطبيقات الخلفية. When turned on, the battery life is increased by 1 minute عند تشغيلها ، يزداد عمر البطارية بمقدار 1 دقيقة When turned on, the battery life is increased by 1 hour عند تشغيله ، يزداد عمر البطارية بمقدار 1 ساعة When turned on, the battery life is increased by 1 hour 1 minute عند تشغيله ، يزداد عمر البطارية بمقدار 1 ساعة و 1 دقيقة When turned on, the battery life is increased by 1 hour %1 minutes عند تشغيلها ، يتم زيادة عمر البطارية بمقدار 1 ساعة٪ 1 دقيقة When turned on, the battery life is increased by %1 hours 1 minute عند تشغيلها ، يزداد عمر البطارية بنسبة 1٪ ساعة و 1 دقيقة When turned on, the battery life is increased by %1 minutes عند تشغيلها ، يزداد عمر البطارية بنسبة 1٪ When turned on, the battery life is increased by %1 hours عند تشغيلها ، يزداد عمر البطارية بنسبة 1٪ ساعة When turned on, the battery life is increased by %1 hours %2 minutes عند تشغيلها ، يزداد عمر البطارية بنسبة ٪1 ساعة ٪2 دقيقة ukui-power-manager/plugin-power/translations/vi.ts0000664000175000017500000003025615167661430021375 0ustar fengfeng Power Power Sức mạnh Require password when sleep/hibernate Yêu cầu mật khẩu khi ngủ / ngủ đông Require password when sleep Yêu cầu mật khẩu khi ngủ Require password when hibernate Yêu cầu mật khẩu khi ngủ đông Password required when waking up the screen Yêu cầu mật khẩu khi đánh thức màn hình Press the power button Nhấn nút nguồn Time to close display Thời gian đóng màn hình Time to sleep Thời gian ngủ Notebook cover Bìa sổ tay Ice freeze mode Chế độ đóng băng Using power Sử dụng năng lượng Using battery Sử dụng pin Automatically run ice freeze mode when low battery Tự động chạy chế độ đóng băng khi pin yếu Battery level is lower than Mức pin thấp hơn Run Chạy Low battery notification Thông báo pin yếu Automatically run saving mode when low battery Tự động chạy chế độ tiết kiệm khi pin yếu Display remaining charging time and usage time Hiển thị thời gian sạc còn lại và thời gian sử dụng General Tổng quát /Power/General Select power plan Chọn gói năng lượng /Power/Select power plan Battery saving plan Kế hoạch tiết kiệm pin /Power/Battery saving plan nothing sự không có blank trống shutdown Shutdown Fractional freezing Đóng băng phân đoạn It can improve the smoothness of the system, and there may be stuttering after shutdown. Nó có thể cải thiện độ mượt mà của hệ thống và có thể bị giật hình sau khi tắt máy. Open battery saving Tiết kiệm pin mở Auto display brightness level Mức độ sáng hiển thị tự động suspend đình chỉ hibernate ngủ đông interactive Tương tác 5min 5 phút 10min 10 phút 15min 15 phút 30min 30 phút 1h 1h 2h 2h never không bao giờ 3h 3 giờ Balance Cân Energy Efficiency Hiệu quả năng lượng Performance Hiệu năng It can improve battery life, but it will freeze background apps. Nó có thể cải thiện thời lượng pin, nhưng nó sẽ đóng băng các ứng dụng nền. When turned on, the battery life is increased by 1 minute Khi được bật, thời lượng pin tăng thêm 1 phút When turned on, the battery life is increased by 1 hour Khi được bật, thời lượng pin tăng thêm 1 giờ When turned on, the battery life is increased by 1 hour 1 minute Khi được bật, thời lượng pin tăng thêm 1 giờ 1 phút When turned on, the battery life is increased by 1 hour %1 minutes Khi được bật, thời lượng pin tăng thêm 1 giờ% 1 phút When turned on, the battery life is increased by %1 hours 1 minute Khi được bật, thời lượng pin sẽ tăng lên% 1 giờ 1 phút When turned on, the battery life is increased by %1 minutes Khi được bật, tuổi thọ pin sẽ tăng lên% 1 phút When turned on, the battery life is increased by %1 hours Khi được bật, tuổi thọ pin được tăng thêm % 1 giờ When turned on, the battery life is increased by %1 hours %2 minutes Khi được bật, thời lượng pin sẽ tăng lên% 1 giờ % 2 phút ukui-power-manager/ukui-upower/0000775000175000017500000000000015167661430015524 5ustar fengfengukui-power-manager/ukui-upower/ukui-upower.pro0000664000175000017500000000225015167661430020541 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2019-06-29T11:18:10 # #------------------------------------------------- QT += core gui dbus greaterThan(QT_MAJOR_VERSION, 4):QT += widgets TARGET = ukui-upower TEMPLATE = app CONFIG += c++14 link_pkgconfig PKGCONFIG += gsettings-qt6 LIBS += -lukui-log4qt SOURCES += main.cpp\ batterydbus.cpp \ batteryinfo/batteryinfo.cpp \ dbus.cpp \ upowerdbus.cpp \ upowerinfo/upowerinfo.cpp HEADERS += batteryinfo/batteryinfo.h \ batterydbus.h \ common/common.h \ dbus.h \ upowerdbus.h \ upowerinfo/upowerinfo.h # Default rules for deployment. qnx: target.path = /tmp/usr/bin else: unix:!android: target.path = /usr/bin !isEmpty(target.path): INSTALLS += target desktop.files += resources/ukui-upower.desktop desktop.path = /etc/xdg/autostart/ INSTALLS += desktop xorg.files += resources/10-monitor.conf xorg.path = /usr/share/X11/xorg.conf.d/ INSTALLS += xorg conf.files += resources/org.ukui.power-manager.gschema.xml conf.path=/usr/share/glib-2.0/schemas/ INSTALLS += conf cf.files += resources/power-manager.conf cf.path = /etc/ukui/power INSTALLS += cf ukui-power-manager/ukui-upower/dbus.h0000664000175000017500000000055715167661430016641 0ustar fengfeng#ifndef DBUS_H #define DBUS_H #include #include #include #include "common/common.h" class DBus : public QObject, protected QDBusContext { Q_OBJECT public: explicit DBus(QObject *parent = nullptr); ~DBus(); protected: void showServiceMsg(); private: QString executeLinuxCmd(QString strCmd); }; #endif // DBUS_H ukui-power-manager/ukui-upower/README.md0000664000175000017500000000047615167661430017012 0ustar fengfengA.使用工具qdbuscpp2xml从dbus.h生成XML文件; qdbuscpp2xml -M dbus.h -o org.ukui.upower.xml B.使用工具qdbusxml2cpp从XML文件生成继承自QDBusAbstractAdaptor的类,供服务端使用 qdbusxml2cpp org.ukui.upower.xml -i dbus.h -a dbus-ukuipower https://blog.51cto.com/9291927/2118468 此方法废弃 ukui-power-manager/ukui-upower/batteryinfo/0000775000175000017500000000000015167661430020052 5ustar fengfengukui-power-manager/ukui-upower/batteryinfo/batteryinfo.h0000664000175000017500000000555215167661430022560 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BATTERYINFO_H #define BATTERYINFO_H #include #include #include #include "../common/common.h" #include "../upowerinfo/upowerinfo.h" struct BatInfo { int warnlevel; bool isPresent; double percentage; uint state; qlonglong timeToEmpty; qlonglong timeToFull; }; class BatteryInfo : public QObject { Q_OBJECT public: explicit BatteryInfo(QObject *parent = nullptr); ~BatteryInfo(); /** * @brief IconName * @return * 图标名称 */ QString IconName(); /** * @brief Percentage * @return * 电量百分比 */ double Percentage(); /** * @brief TimeToFull * @return * 充电过程中,还有多久充满电 */ int TimeToFull(); /** * @brief TimeToEmpty * @return * 放电过程 还有多久耗尽 */ int TimeToEmpty(); int getBatteryState(); bool IsPresent(); bool LowBatteryState(); private: QDBusInterface *iface; QGSettings *mPowerManagementGsettings; UPowerInfo *mUpower; bool batteryState; /** * @brief mPercentage * 当前电量百分比 */ double mPercentage; /** * @brief mSetPercentageLow * 用户设置的低电量百分比 */ int mSetPercentageLow; /** * @brief mPercentageAction * 用户设置的极低电量百分比 */ int mPercentageAction; /** * @brief mLowBatteryState * 低电量状态 */ bool mLowBatteryState; bool mVeryLowBatteryState; QString mIconMessage; BatInfo mBat1; void initBatteryInfo(BatInfo &data); void readSettings(); void getBatteryInfo(); void dealLowBatteryMessage(const bool &state); void dealBatteryIconMessage(const bool &state,const double &precentage); void msgAnalysis(QDBusMessage); void putBatteryInfo(QMap &map, BatInfo &data); void showBatteryInfo(); private slots: void dealMessage(QDBusMessage); signals: void LowBatteryChanged(bool); void VeryLowBatteryChanged(bool); void BatteryIconChanged(QString); void PercentageChanged(double); }; #endif // BATTERYINFO_H ukui-power-manager/ukui-upower/batteryinfo/batteryinfo.cpp0000664000175000017500000002111315167661430023102 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "batteryinfo.h" BatteryInfo::BatteryInfo(QObject *parent) : QObject(parent) { const QByteArray id("org.ukui.power-manager"); mPowerManagementGsettings = new QGSettings(id); mUpower = new UPowerInfo; QString batteryPath = mUpower->getBatteryPath(); iface = new QDBusInterface(UPOWER_SERVICE, batteryPath, FREEDESKTOP_UPOWER, QDBusConnection::systemBus()); initBatteryInfo(mBat1); showBatteryInfo(); connect(mPowerManagementGsettings, &QGSettings::changed, this, [=] { readSettings(); }); if (batteryPath.contains("battery_")) { QDBusConnection::systemBus().connect(UPOWER_SERVICE, batteryPath, FREEDESKTOP_UPOWER, "PropertiesChanged", this, SLOT(dealMessage(QDBusMessage))); } } BatteryInfo::~BatteryInfo() { delete iface; delete mUpower; delete mPowerManagementGsettings; } void BatteryInfo::initBatteryInfo(BatInfo &data) { readSettings(); mLowBatteryState = false; QDBusMessage msg = iface->call("GetAll","org.freedesktop.UPower.Device"); qDebug() << "get all bat msg type :" << msg.type(); if (msg.type() == QDBusMessage::ReplyMessage) { const QDBusArgument &dbusArg = msg.arguments().at(0).value(); QMap map; dbusArg >> map; data.isPresent = (map.value(QString("IsPresent")).toBool()); data.percentage = map.value(QString("Percentage")).toDouble(); data.percentage = ( (float)( (int)( (data.percentage + 0.05) * 10 ) ) ) / 10; data.state = map.value(QString("State")).toInt(); data.timeToEmpty = map.value(QString("TimeToEmpty")).toLongLong(); data.timeToFull = map.value(QString("TimeToFull")).toLongLong(); data.warnlevel = map.value(QString("WarningLevel")).toInt(); } else { qDebug() << "init battery data faile"; } } void BatteryInfo::dealMessage(QDBusMessage msg) { readSettings(); getBatteryInfo(); dealLowBatteryMessage(batteryState); dealBatteryIconMessage(batteryState, mPercentage); msgAnalysis(msg); } void BatteryInfo::readSettings() { mSetPercentageLow = mPowerManagementGsettings->get("percentageLow").toInt(); mPercentageAction = mPowerManagementGsettings->get("percentageAction").toInt(); } void BatteryInfo::getBatteryInfo() { QThread::msleep(500); batteryState = mUpower->OnBattery(); mPercentage = Percentage(); } void BatteryInfo::msgAnalysis(QDBusMessage batData) { const QDBusArgument &dbusArgs = batData.arguments().at(1).value(); QMap map; dbusArgs >> map; putBatteryInfo(map,mBat1); showBatteryInfo(); } void BatteryInfo::putBatteryInfo(QMap &map, BatInfo &data) { if (map.contains("TimeToFull")) { data.timeToFull = map.value(QString("TimeToFull")).toLongLong(); } if (map.contains("TimeToEmpty")) { data.timeToEmpty = map.value(QString("TimeToEmpty")).toLongLong(); } if (map.contains("WarnLevel")) { data.warnlevel = map.value(QString("WarnLevel")).toInt(); } if (map.contains("State")) { data.state = map.value(QString("State")).toUInt(); } if (map.contains("Percentage")) { data.percentage = map.value(QString("Percentage")).toDouble(); data.percentage = ( (float)( (int)( (data.percentage + 0.05) * 10 ) ) ) / 10; emit PercentageChanged(data.percentage); } if (map.contains("IsPresent")) { data.isPresent = (map.value(QString("IsPresent")).toBool()); } } void BatteryInfo::showBatteryInfo() { qDebug() << "TimeToFull" << mBat1.timeToFull; qDebug() << "TimeToEmpty" << mBat1.timeToEmpty; qDebug() << "WarnLevel" << mBat1.warnlevel; qDebug() << "State" << mBat1.state; qDebug() << "Percentage" << mBat1.percentage; qDebug() << "IsPresent" << mBat1.isPresent; } QString BatteryInfo::IconName() { getBatteryInfo(); double num = mPercentage; if(!IsPresent()){ mIconMessage = QString("battery-error-charging-symbolic"); }else if (true == batteryState) { mIconMessage = QString("battery-level-%1-symbolic").arg((int)num / 10 * 10); } else { mIconMessage = QString("battery-level-%1-charging-symbolic").arg((int)num / 10 * 10); } return mIconMessage; } double BatteryInfo::Percentage() { double value; QDBusReply reply = iface->call("Get", UPOWER_DIVICES_SERVICE, "Percentage"); if (reply.isValid()) { value = reply.value().toDouble(); return value; } else { qDebug() << "Get percentage failed"; return -1.0; } } int BatteryInfo::TimeToFull() { // QDBusInterface iface(UPOWER_SERVICE,UPOWER_DISPLAY_PATH, // FREEDESKTOP_UPOWER, // QDBusConnection::systemBus()); QDBusReply reply = iface->call("Get", UPOWER_DIVICES_SERVICE, "TimeToFull"); if (reply.isValid()) { return reply.value().toInt(); } else { qDebug() << "Get time to full failed"; return -1; } } int BatteryInfo::TimeToEmpty() { QDBusInterface iface(UPOWER_SERVICE, UPOWER_DISPLAY_PATH, FREEDESKTOP_UPOWER, QDBusConnection::systemBus()); QDBusReply reply = iface.call("Get", UPOWER_DIVICES_SERVICE, "TimeToEmpty"); if (reply.isValid()) { return reply.value().toInt(); } else { qDebug() << "Get time to empty failed"; return -1; } } bool BatteryInfo::IsPresent() { QDBusReply reply = iface->call("Get", UPOWER_DIVICES_SERVICE, "IsPresent"); if (reply.isValid()) { return reply.value().toInt(); } else { qDebug() << "Get is present failed"; return false; } } bool BatteryInfo::LowBatteryState() { readSettings(); getBatteryInfo(); if (mSetPercentageLow > mPercentage) { return true; } else { qDebug() << "Get low battery state failed"; return false; } } int BatteryInfo::getBatteryState() { QDBusReply reply = iface->call("Get", UPOWER_DIVICES_SERVICE, "State"); if (reply.isValid()) { return reply.value().toInt(); } else { qDebug() << "Get Battery State failed"; return -1; } } void BatteryInfo::dealLowBatteryMessage(const bool &state) { if (state) { if (mSetPercentageLow >= mPercentage) { if (!mLowBatteryState) { mLowBatteryState = true; emit LowBatteryChanged(mLowBatteryState); } if (mPercentageAction > mPercentage) { mVeryLowBatteryState = true; emit VeryLowBatteryChanged(mVeryLowBatteryState); } } else { if (mLowBatteryState) { mLowBatteryState = false; emit LowBatteryChanged(mLowBatteryState); } if (mVeryLowBatteryState) { mVeryLowBatteryState = false; emit VeryLowBatteryChanged(mVeryLowBatteryState); } } } else { if (mLowBatteryState) { mLowBatteryState = false; emit LowBatteryChanged(mLowBatteryState); } if (mVeryLowBatteryState) { mVeryLowBatteryState = false; emit VeryLowBatteryChanged(mVeryLowBatteryState); } } } void BatteryInfo::dealBatteryIconMessage(const bool &state, const double &precentage) { double num = precentage; if(!IsPresent()){ mIconMessage = QString("battery-error-charging-symbolic"); } else if (true == state) { mIconMessage = QString("battery-level-%1-symbolic").arg((int)num / 10 * 10); } else { mIconMessage = QString("battery-level-%1-charging-symbolic").arg((int)num / 10 * 10); } emit BatteryIconChanged(mIconMessage); } ukui-power-manager/ukui-upower/dbus-ukuipower.h0000664000175000017500000000527015167661415020671 0ustar fengfeng/* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp org.ukui.upower.xml -i dbus.h -a dbus-ukuipower * * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. * * This is an auto-generated file. * This file may have been hand-edited. Look for HAND-EDIT comments * before re-generating it. */ #ifndef DBUS-UKUIPOWER_H #define DBUS-UKUIPOWER_H #include #include #include "dbus.h" QT_BEGIN_NAMESPACE class QByteArray; template class QList; template class QMap; class QString; class QStringList; class QVariant; QT_END_NAMESPACE /* * Adaptor class for interface org.ukui.upower */ class UpowerAdaptor: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.ukui.upower") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") public: UpowerAdaptor(QObject *parent); virtual ~UpowerAdaptor(); public: // PROPERTIES public Q_SLOTS: // METHODS int BatteryState(); bool CanAdjustBacklight(); QString CanHibernate(); QString DaemonVersion(); QString IconName(); bool IsPresent(); bool LowBattery(); QString MachineType(); bool OnBattery(); double Percentage(); int TimeToEmpty(); int TimeToFull(); QString UPowerVersion(); Q_SIGNALS: // SIGNALS }; #endif ukui-power-manager/ukui-upower/resources/0000775000175000017500000000000015167661430017536 5ustar fengfengukui-power-manager/ukui-upower/resources/99-upower-wake-up-usb-device.rules0000664000175000017500000000022515167661415025767 0ustar fengfengSUBSYSTEMS=="usb", ATTRS{product}=="*Mouse",ATTR{power/wakeup}="enabled" SUBSYSTEMS=="usb", ATTRS{product}=="*Keyboard",ATTR{power/wakeup}="enabled" ukui-power-manager/ukui-upower/resources/ukui-upower.desktop0000664000175000017500000000025715167661415023434 0ustar fengfeng[Desktop Entry] Name=Ukui-Upower Icon=ukui-power-manager Exec=ukui-upower Terminal=false Type=Application NoDisplay=true Categories= OnlyShowIn=UKUI; X-UKUI-AutoRestart=true ukui-power-manager/ukui-upower/resources/org.ukui.power-manager.gschema.xml0000664000175000017500000005335015167661430026202 0ustar fengfeng 'suspend' Whether to hibernate, suspend or do nothing when inactive The type of sleeping that should be performed when the computer is inactive. 'suspend' Battery critical low action The action to take when the battery is critically low. true If the battery event should occur when the lid is shut and the power disconnected If the battery lid close event should occur (for example 'Suspend when lid closed on battery') when the lid is previously shut and the AC power disconnected at a later time. 'suspend' Whether to hibernate, suspend or do nothing when inactive The type of sleeping that should be performed when the computer is inactive. 'shutdown' UPS critical low action The action to take when the UPS is critically low. 'hibernate' UPS low power action The action to take when the UPS is low. true Allow backlight brightness adjustment If the screen brightness should be changed when switching between AC and battery power. true Reduce the backlight brightness when on battery power If the screen should be reduced in brightness when the computer is on battery power. true Reduce the keyboard backlight when on battery power If the keyboard backlight brightness should be reduced when the computer is on battery power 100 Keyboard backlight brightness when on AC power. Percent brightness to set keyboard backlight at when on AC power. Legal values are between 0 and 100. 50 Percent to reduce keyboard backlight by when on battery power. The percentage to reduce the keyboard backlight by when on battery power. For example, if set to '60', the backlight will be cut by 40% on battery power. Legal values are between 0 and 100. 75 Percent to reduce keyboard backlight by when idle. The percentage to reduce the keyboard backlight by when idle. For example, if set to '60', the backlight will be cut by 40% when idle. Legal values are between 0 and 100. 70 The brightness of the screen when idle This is the laptop panel screen brightness used when the session is idle. Only valid when use-time-for-policy is true. true Dim the screen after a period of inactivity when on battery power If the screen should be dimmed to save power when the computer is idle when on battery power. 60 The default amount of time to dim the screen after idle The default amount of time to dim the screen after idle. 50 LCD dimming amount when on battery The amount to dim the brightness of the display when on battery power. Possible values are between 0 and 100. false Dim the screen after a period of inactivity when on AC power If the screen should be dimmed to save power when the computer is idle when on AC power. 'off' Method used to blank screen on AC The DPMS method used to blank the screen when on AC power. 'off' Method used to blank screen on battery The DPMS method used to blank the screen when on battery power. -1.0 LCD brightness when on AC The brightness of the display when on AC power. Possible values are between 0.0 and 100.0. 100.0 LCD brightness when on BAT The brightness of the display when on BAT power. Possible values are between 0.0 and 100.0. false Brightness enhancement switch Brightness enhancement Switch‌ – true indicates the brightness boost is ‌enabled‌, while false means it is ‌disabled‌. 'suspend' Suspend button action The action to take when the system suspend button is pressed. 'hibernate' Hibernate button action The action to take when the system hibernate button is pressed. 'interactive' Power button action The action to take when the system power button is pressed. 'suspend' Laptop lid close action on battery The action to take when the laptop lid is closed and the laptop is on battery power. 'suspend' Laptop lid close action when on AC The action to take when the laptop lid is closed and the laptop is on AC power. true Whether to use time-based notifications If time based notifications should be used. If set to false, then the percentage change is used instead, which may fix a broken ACPI BIOS. false Check CPU load before sleeping If the CPU load should be checked before doing the idle action. false Whether NetworkManager should be connected and disconnected on sleep. Whether NetworkManager should disconnect before suspending or hibernating and connect on resume. true Use ukui-screensaver lock setting Whether to use the screen lock setting of ukui-screensaver to decide if the screen is locked after a hibernate, suspend or blank screen. true Lock screen when blanked Whether the screen is locked when the screen is turned off. Only used if lock-use-screensaver is false. true Lock screen on suspend Whether the screen is locked when the computer wakes up from a suspend. Only used if lock-use-screensaver is false. true Lock screen on hibernate Whether the screen is locked when the computer wakes up from a hibernate. Only used if lock-use-screensaver is false. false Lock GNOME keyring on sleep Whether the GNOME keyring is locked before the computer enters suspend. This means the keyring will have to be unlocked on resume. true Lock GNOME keyring on sleep Whether the GNOME keyring is locked before the computer enters hibernate. This means the keyring will have to be unlocked on resume. true If we should show the low capacity warning for a broken battery If we should show the low capacity warning for a broken battery. true Notify when AC adapter is disconnected If the user should be notified when the AC adapter is disconnected. false Notify when fully charged If a notification message should be displayed when the battery is fully charged. true Notify on a sleep failure If a notification message should be displayed after suspend or hibernate failed. '' The URI to show to the user on sleep failure When sleep fails we can show the user a button to help fix the situation. Leave this blank if the button should not be shown. true Notify on a low power If a notification message should be displayed when the battery is getting low. true Whether we should show the history data points Whether we should show the history data points in the statistics window. true Whether we should smooth the history data Whether we should smooth the history data in the graph. 'power' The default graph type to show for history The default graph type to show in the history window. 21600 The maximum time displayed for history The maximum duration of time displayed on the x-axis of the history graph. true Whether we should show the stats data points Whether we should show the stats data points in the statistics window. true Whether we should smooth the stats data Whether we should smooth the stats data in the graph. 'power' The default graph type to show for stats The default graph type to show in the stats window. 0 The index of the page number to show by default The index of the page number to show by default which is used to return focus to the correct page. '' The ID of the last device selected The identifier of the last device which is used to return focus to the correct device. 20 Percentage considered low The percentage of the battery when it is considered low. Only valid when use-time-for-policy is false. 10 Percentage considered critical The percentage of the battery when it is considered critical. Only valid when use-time-for-policy is false. 5 Percentage action is taken The percentage of the battery when the critical action is performed. Only valid when use-time-for-policy is false. false percentage low reduce brightness percentage low reduce brightness. 1200 The time remaining when low The time remaining in seconds of the battery when it is considered low. Only valid when use-time-for-policy is true. 300 The time remaining when critical The time remaining in seconds of the battery when it is considered critical. Only valid when use-time-for-policy is true. 120 The time remaining when action is taken The time remaining in seconds of the battery when critical action is taken. Only valid when use-time-for-policy is true. 900 Sleep timeout computer when on battery The amount of time in seconds the computer on battery power needs to be inactive before it goes to sleep. 1800 Sleep timeout computer when on AC The amount of time in seconds the computer on AC power needs to be inactive before it goes to sleep. 14400 hibernate timeout computer when on battery The amount of time in seconds the computer on battery power needs to be inactive before it goes to hibernate. 14400 hibernate timeout computer when on AC The amount of time in seconds the computer on AC power needs to be inactive before it goes to hibernate. 0 Sleep timeout computer when on UPS The amount of time in seconds the computer on UPS power needs to be inactive before it goes to sleep. 600 Sleep timeout display when on AC The amount of time in seconds before the display goes to sleep when the computer is on AC power. 300 Sleep timeout display when on battery The amount of time in seconds the computer on battery power needs to be inactive before the display goes to sleep. 600 Sleep timeout display when on UPS The amount of time in seconds the computer on UPS power needs to be inactive before the display goes to sleep. true If sounds should be used If sounds should be used when the power is critically low, or inhibit requests have stopped the policy action. true If preferences and statistics items should be shown in the context menu false If power policy mode should be auto switched when plugged in and out false If power policy mode should be auto switched when plugged in and out false Switch to a lower power policy when the system is idle 2 power policy mode 1 power policy current 1 power policy current 3 power policy current 1 power policy current 1 power policy current 0 power policy current 1 power policy current 'present' When to show the notification icon Display options for the notification icon. false init power manager config false Adjust the power mode strategy based on local mainline information ukui-power-manager/ukui-upower/resources/10-monitor.conf0000664000175000017500000000020415167661415022311 0ustar fengfengSection "ServerFlags" option "StandbyTime" "0" option "SuspendTime" "0" option "OffTime" "0" option "BlankTime" "0" EndSection ukui-power-manager/ukui-upower/main.cpp0000664000175000017500000000327315167661430017161 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "upowerdbus.h" #include "batterydbus.h" int main(int argc, char *argv[]) { initUkuiLog4qt("ukui-upower"); QApplication a(argc, argv); std::unique_ptr dbus = std::make_unique(); std::unique_ptr batDbus = std::make_unique(); QDBusConnection con = QDBusConnection::sessionBus(); if (!con.registerService("org.ukui.upower")) { qWarning() << "QDbus register service failed reason:" << con.lastError(); exit(0); } if (!con.registerObject("/upower", dbus.get(), QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals) || !con.registerObject( "/upower/BatteryInfo", batDbus.get(), QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals)) { qWarning() << "QDbus register object failed reason:" << con.lastError(); exit(1); } return a.exec(); } ukui-power-manager/ukui-upower/org.ukui.upower.xml0000664000175000017500000000243115167661415021334 0ustar fengfeng ukui-power-manager/ukui-upower/upowerdbus.h0000664000175000017500000000416015167661430020075 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPOWERDBUS_H #define UPOWERDBUS_H #include "upowerinfo/upowerinfo.h" #include class UpowerDBus : public DBus { Q_OBJECT Q_CLASSINFO("D-Bus Interface","org.ukui.upower") public: UpowerDBus(); ~UpowerDBus(); public slots: /** * @brief UPowerVersion * ukui-upower版本 * @return */ QString UPowerVersion(void); /** * @brief CanHibernate * @return * 是否可以休眠的接口 * 或可直接调用login1 的 * 重新封装的意义在于可以针对部分机型做特殊处理 * 并且可以 */ QString CanHibernate(void); /** * @brief MachineType * @return * 机器类型判断 */ QString MachineType(); /** * @brief OnBattery * AC状态还是DC状态 * @return */ bool OnBattery(); /** * @brief LidIsClosed * 当前合盖状态 * @return */ bool LidIsClosed(); /** * @brief DaemonVersion * 判断upower版本 * @return */ QString DaemonVersion(); /** * @brief CanAdjustBacklight * 能否调节背光 * @return */ bool CanAdjustBacklight(); signals: /** * @brief PowerState */ void PowerState(bool); /** * @brief LidState */ void LidState(bool); private: UPowerInfo *upowerinfo; void dealPowerState(bool); void dealLidState(bool); }; #endif // UPOWERDBUS_H ukui-power-manager/ukui-upower/upowerdbus.cpp0000664000175000017500000000365015167661430020433 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upowerdbus.h" UpowerDBus::UpowerDBus() { upowerinfo = new UPowerInfo; upowerinfo->initUpowerInfo(); connect(upowerinfo, &UPowerInfo::acChanged, this, &UpowerDBus::dealPowerState); connect(upowerinfo, &UPowerInfo::lidChanged, this, &UpowerDBus::dealLidState); } UpowerDBus::~UpowerDBus() { delete upowerinfo; } QString UpowerDBus::UPowerVersion() { showServiceMsg(); return "3.1"; } QString UpowerDBus::CanHibernate() { showServiceMsg(); return upowerinfo->CanHibernate(); } QString UpowerDBus::MachineType() { showServiceMsg(); return upowerinfo->MachineType(); } bool UpowerDBus::OnBattery() { showServiceMsg(); return upowerinfo->OnBattery(); } bool UpowerDBus::LidIsClosed() { showServiceMsg(); return upowerinfo->LidIsClosed(); } QString UpowerDBus::DaemonVersion() { showServiceMsg(); return upowerinfo->DaemonVersion(); } //***************************************** /******************************************/ bool UpowerDBus::CanAdjustBacklight() { showServiceMsg(); return upowerinfo->CanAdjustBacklight(); } void UpowerDBus::dealPowerState(bool state) { emit PowerState(state); } void UpowerDBus::dealLidState(bool state) { emit LidState(state); } ukui-power-manager/ukui-upower/common/0000775000175000017500000000000015167661430017014 5ustar fengfengukui-power-manager/ukui-upower/common/common.h0000664000175000017500000000226515167661430020462 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COMMON_H #define COMMON_H #define FREEDESKTOP_UPOWER "org.freedesktop.DBus.Properties" #define UPOWER_INTERFACE "org.freedesktop.UPower" #define UPOWER_PATH "/org/freedesktop/UPower" #define UPOWER_SERVICE "org.freedesktop.UPower" #define UPOWER_DISPLAY_PATH "/org/freedesktop/UPower/devices/DisplayDevice" #define UPOWER_DIVICES_SERVICE "org.freedesktop.UPower.Device" #endif // COMMON_H ukui-power-manager/ukui-upower/batterydbus.cpp0000664000175000017500000000353415167661430020565 0ustar fengfeng#include "batterydbus.h" BatteryDBus::BatteryDBus() { batteryinfo = new BatteryInfo; connect(batteryinfo, &BatteryInfo::LowBatteryChanged, this, &BatteryDBus::dealLowBattery); connect(batteryinfo, &BatteryInfo::VeryLowBatteryChanged, this, &BatteryDBus::dealVeryLowBattery); connect(batteryinfo, &BatteryInfo::BatteryIconChanged, this, &BatteryDBus::dealBatteryIcon); connect(batteryinfo, &BatteryInfo::PercentageChanged, this, &BatteryDBus::PercentageChanged); } BatteryDBus::~BatteryDBus() { delete batteryinfo; } QString BatteryDBus::IconName() { showServiceMsg(); return batteryinfo->IconName(); } double BatteryDBus::Percentage() { showServiceMsg(); return batteryinfo->Percentage(); } int BatteryDBus::TimeToFull() { showServiceMsg(); return batteryinfo->TimeToFull(); } int BatteryDBus::TimeToEmpty() { showServiceMsg(); return batteryinfo->TimeToEmpty(); } bool BatteryDBus::IsPresent() { showServiceMsg(); return batteryinfo->IsPresent(); } int BatteryDBus::BatteryState() { showServiceMsg(); return batteryinfo->getBatteryState(); } bool BatteryDBus::LowBattery() { showServiceMsg(); return batteryinfo->LowBatteryState(); } void BatteryDBus::dealLowBattery(bool state) { emit LowBatteryState(state); } void BatteryDBus::dealVeryLowBattery(bool state) { emit VeryLowBatteryState(state); } void BatteryDBus::dealBatteryIcon(QString msg) { emit BatteryIcon(msg); } QString BatteryDBus::GetBatteryTooltip() { showServiceMsg(); return m_tooltip; } void BatteryDBus::SetBatteryTooltip(const QString &tooltip) { m_tooltip = tooltip; emit BatteryTooltip(m_tooltip); } void BatteryDBus::SetShowIcon(const bool &show) { m_showIcon = show; emit BatteryShowIcon(m_showIcon); } bool BatteryDBus::ShowIcon(){ showServiceMsg(); return m_showIcon; }ukui-power-manager/ukui-upower/upowerinfo/0000775000175000017500000000000015167661430017721 5ustar fengfengukui-power-manager/ukui-upower/upowerinfo/upowerinfo.cpp0000664000175000017500000001634215167661430022630 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upowerinfo.h" UPowerInfo::UPowerInfo(QObject *parent) : QObject(parent) { iface = new QDBusInterface(UPOWER_SERVICE, UPOWER_PATH, FREEDESKTOP_UPOWER, QDBusConnection::systemBus()); m_hasBattery = false; mOnBattery = false; mLidIsClosed = false; } UPowerInfo::~UPowerInfo() { delete iface; } void UPowerInfo::initUpowerInfo() { getBatteryPath(); if (true == m_hasBattery) { QDBusConnection::systemBus().connect(UPOWER_SERVICE, UPOWER_PATH, FREEDESKTOP_UPOWER, "PropertiesChanged", this, SLOT(dealMessage(QDBusMessage))); mOnBattery = OnBattery(); mLidIsClosed = LidIsClosed(); } } QString UPowerInfo::UPowerVersion() { return "3.1"; } QString UPowerInfo::CanHibernate() { QDBusInterface interface( "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", QDBusConnection::systemBus()); if (!interface.isValid()) { qCritical() << QDBusConnection::sessionBus().lastError().message(); } /*调用远程的 CanHibernate 方法,判断是否可以执行休眠的操作,返回值为yes为允许执行休眠,no为无法执行休眠 * na为交换分区不足*/ QDBusReply reply = interface.call("CanHibernate"); if (reply.isValid()) { return reply.value(); } else { return "Call Dbus method failed"; } } QString UPowerInfo::MachineType() { QDBusReply reply = iface->call("Get", UPOWER_SERVICE, "LidIsPresent"); if (reply.isValid()) { if (true == reply.value().toBool()) { return "book"; } else { return "pc"; } } else { qDebug() << "Get lid is present failed"; return "Get lid is present failed"; } } bool UPowerInfo::CanAdjustBacklight() { QDBusInterface controlCenterDBus("com.control.center.qt.systemdbus", "/", "com.control.center.interface", QDBusConnection::systemBus()); QDBusReply reply = controlCenterDBus.call("getDmidecodeType"); qDebug() << "dmidecode type:" << reply.value(); if (0 == QString::compare("desktop", reply.value(), Qt::CaseInsensitive)) { return false; } QDir dir("/sys/class/backlight"); QStringList filter; QStringList filterAll; filter << ".*"; dir.setNameFilters(filter); QList fileInfo = dir.entryInfoList(filter); int num = fileInfo.count(); fileInfo = dir.entryInfoList(filterAll); int numAll = fileInfo.count(); if (0 < numAll - num) { return true; } else { return false; } } bool UPowerInfo::OnBattery() { // QDBusInterface iface(UPOWER_SERVICE,UPOWER_PATH, // FREEDESKTOP_UPOWER, // QDBusConnection::systemBus()); QDBusReply reply = iface->call("Get", UPOWER_SERVICE, "OnBattery"); if (reply.isValid()) { return reply.value().toBool(); } else { qDebug() << "Get on battery failed"; return false; } } bool UPowerInfo::LidIsClosed() { QDBusReply reply = iface->call("Get", UPOWER_SERVICE, "LidIsClosed"); if (reply.isValid()) { return reply.value().toBool(); } else { qDebug() << "Get lid is close failed"; return false; } } QString UPowerInfo::DaemonVersion() { // QDBusInterface iface(UPOWER_SERVICE,UPOWER_PATH, // FREEDESKTOP_UPOWER, // QDBusConnection::systemBus()); QDBusReply reply = iface->call("Get", UPOWER_SERVICE, "DaemonVersion"); if (reply.isValid()) { return reply.value().toString(); } else { qDebug() << "Get version failed"; return "Get version failed!"; } } QString UPowerInfo::getBatteryPath() { QString batteryPath = ""; QDBusInterface dface(UPOWER_SERVICE, UPOWER_PATH, UPOWER_INTERFACE, QDBusConnection::systemBus()); QDBusReply> reply = dface.call("EnumerateDevices"); if (dface.isValid()) { for (QDBusObjectPath op : reply.value()) { int upDeviceType = getDeviceType(op.path()); if (up_device_type_battery == upDeviceType) { batteryPath = op.path(); m_hasBattery = true; break; } } } else { qDebug() << "Enumerate devices failed"; } return batteryPath; } int UPowerInfo::getDeviceType(const QString &dBusPath) { qDebug() << "device dBus object path:" << dBusPath; // upower dbus device path /org/freedesktop/UPower/devices/keyboard_hidpp_battery_0 QString deviceName = dBusPath.split('/').last(); QString deviceType = deviceName.split('_').first(); if ("keyboard" == deviceType) { return up_device_type_keyboard; } if ("mouse" == deviceType) { return up_device_type_mouse; } QDBusInterface dBusInterface("org.freedesktop.UPower", dBusPath, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus()); QDBusReply reply = dBusInterface.call("Get", "org.freedesktop.UPower.Device", "Type"); if (reply.isValid()) { return reply.value().toInt(); } else { qDebug() << "Get device type failed"; return up_device_type_unknown; } } void UPowerInfo::dealMessage(QDBusMessage msg) { QString key; QVariant value; QList outArgs = msg.arguments(); QVariant upowerDate = outArgs.at(1); const QDBusArgument &dbusArgs = upowerDate.value(); dbusArgs.beginMap(); while (!dbusArgs.atEnd()) { dbusArgs.beginMapEntry(); dbusArgs >> key >> value; dbusArgs.endMapEntry(); } dbusArgs.endMap(); if ("LidIsClosed" == key) { dealLidMessage(value.toBool()); } else if ("OnBattery" == key) { dealPowerMessage(value.toBool()); } else { qDebug() << "Upower message get failed"; } } void UPowerInfo::dealPowerMessage(bool value) { if (mOnBattery != value) { mOnBattery = value; emit acChanged(mOnBattery); } } void UPowerInfo::dealLidMessage(bool value) { if (mLidIsClosed != value) { mLidIsClosed = value; emit lidChanged(mLidIsClosed); } } ukui-power-manager/ukui-upower/upowerinfo/upowerinfo.h0000664000175000017500000000502715167661430022273 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPOWERINFO_H #define UPOWERINFO_H #include #include #include #include "../common/common.h" enum up_device_type { up_device_type_unknown = 0, up_device_type_line_power, up_device_type_battery, up_device_type_ups, up_device_type_monitor, up_device_type_mouse, up_device_type_keyboard, up_device_type_pda, up_device_type_phone, up_device_type_media_player, up_device_type_tablet, up_device_type_computer, up_device_type_max }; class UPowerInfo : public QObject { Q_OBJECT public: explicit UPowerInfo(QObject *parent = nullptr); ~UPowerInfo(); /** * @brief initUpowerInfo * 电池信息初始化 */ void initUpowerInfo(); /** * @brief UPowerVersion * @return * UPower版本 */ QString UPowerVersion(void); /** * @brief CanHibernate * @return * 是否可以休眠的接口 * 或可直接调用login1 的 * 重新封装的意义在于可以针对部分机型做特殊处理 * 并且可以 */ QString CanHibernate(void); /** * @brief MachineType * @return * 机器类型判断 */ QString MachineType(); bool CanAdjustBacklight(); bool OnBattery(); bool LidIsClosed(); QString DaemonVersion(); QString getBatteryPath(); private slots: void dealMessage(QDBusMessage); private: void dealPowerMessage(bool); void dealLidMessage(bool); QDBusInterface *iface; bool m_hasBattery; bool mOnBattery; bool mLidIsClosed; int getDeviceType(const QString &dBusPath); signals: /** * @brief acChanged * 电源状态改变信号 */ void acChanged(bool ); /** * @brief acChanged * 合盖状态改变信号 */ void lidChanged(bool ); }; #endif // UPOWERINFO_H ukui-power-manager/ukui-upower/org.ukui.power.xml0000664000175000017500000000202515167661415021146 0ustar fengfeng ukui-power-manager/ukui-upower/batterydbus.h0000664000175000017500000000333115167661430020225 0ustar fengfeng#ifndef BATTERYDBUS_H #define BATTERYDBUS_H #include #include class BatteryDBus : public DBus { Q_OBJECT Q_CLASSINFO("D-Bus Interface","org.ukui.upower.battery") public: BatteryDBus(); ~BatteryDBus(); public slots: /** * @brief IconName * @return * 图标名称 */ QString IconName(); /** * @brief Percentage * @return * 电量百分比 */ double Percentage(); /** * @brief TimeToFull * @return * 充电过程中,还有多久充满电 */ int TimeToFull(); /** * @brief TimeToEmpty * @return * 放电过程 还有多久耗尽 */ int TimeToEmpty(); /** * @brief IsPresent * 电池是否存在 * @return */ bool IsPresent(); /** * @brief BatteryState * 电池状态 * @return */ int BatteryState(); /** * @brief LowBattery * 低电量 * @return */ bool LowBattery(); bool ShowIcon(); QString GetBatteryTooltip(); void SetBatteryTooltip(const QString &tooltip); void SetShowIcon(const bool &show); signals: /** * @brief lowBatteryState * @return * 低电量状态信号 */ void LowBatteryState(bool); /** * @brief VeryLowBatteryState */ void VeryLowBatteryState(bool); void BatteryIcon(QString); void BatteryTooltip(QString); void BatteryShowIcon(bool); void PercentageChanged(double); private: BatteryInfo *batteryinfo; QString m_tooltip; bool m_showIcon = false; void dealLowBattery(bool); void dealVeryLowBattery(bool); void dealBatteryIcon(QString); }; #endif // BATTERYDBUS_H ukui-power-manager/ukui-upower/dbus.cpp0000664000175000017500000000152015167661430017163 0ustar fengfeng#include "dbus.h" DBus::DBus(QObject *parent) : QObject(parent), QDBusContext(){} DBus::~DBus() {} void DBus::showServiceMsg() { QDBusConnection con = connection(); QDBusMessage msg = message(); int str = con.interface()->servicePid(msg.service()).value(); qDebug() << "Sender Name" << con.interface()->serviceOwner(msg.service()).value(); qDebug() << "Sender Uid" << con.interface()->serviceUid(msg.service()).value(); qDebug() << "Sender Pid " << str; qDebug() << executeLinuxCmd(QString::number(str)); } QString DBus::executeLinuxCmd(QString strCmd) { QProcess process; process.start("bash", QStringList() << "-c" << QString("ps -p %1 -o comm=").arg(strCmd)); process.waitForFinished(); QString strResult = process.readAllStandardOutput() + process.readAllStandardError(); return strResult; } ukui-power-manager/ukui-upower/dbus-ukuipower.cpp0000664000175000017500000000666115167661415021231 0ustar fengfeng/* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp org.ukui.upower.xml -i dbus.h -a dbus-ukuipower * * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. * * This is an auto-generated file. * Do not edit! All changes made to it will be lost. */ #include "dbus-ukuipower.h" #include #include #include #include #include #include #include /* * Implementation of adaptor class UpowerAdaptor */ UpowerAdaptor::UpowerAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent) { // constructor setAutoRelaySignals(true); } UpowerAdaptor::~UpowerAdaptor() { // destructor } int UpowerAdaptor::BatteryState() { // handle method call org.ukui.upower.BatteryState int out0; QMetaObject::invokeMethod(parent(), "BatteryState", Q_RETURN_ARG(int, out0)); return out0; } bool UpowerAdaptor::CanAdjustBacklight() { // handle method call org.ukui.upower.CanAdjustBacklight bool out0; QMetaObject::invokeMethod(parent(), "CanAdjustBacklight", Q_RETURN_ARG(bool, out0)); return out0; } QString UpowerAdaptor::CanHibernate() { // handle method call org.ukui.upower.CanHibernate QString out0; QMetaObject::invokeMethod(parent(), "CanHibernate", Q_RETURN_ARG(QString, out0)); return out0; } QString UpowerAdaptor::DaemonVersion() { // handle method call org.ukui.upower.DaemonVersion QString out0; QMetaObject::invokeMethod(parent(), "DaemonVersion", Q_RETURN_ARG(QString, out0)); return out0; } QString UpowerAdaptor::IconName() { // handle method call org.ukui.upower.IconName QString out0; QMetaObject::invokeMethod(parent(), "IconName", Q_RETURN_ARG(QString, out0)); return out0; } bool UpowerAdaptor::IsPresent() { // handle method call org.ukui.upower.IsPresent bool out0; QMetaObject::invokeMethod(parent(), "IsPresent", Q_RETURN_ARG(bool, out0)); return out0; } bool UpowerAdaptor::LowBattery() { // handle method call org.ukui.upower.LowBattery bool out0; QMetaObject::invokeMethod(parent(), "LowBattery", Q_RETURN_ARG(bool, out0)); return out0; } QString UpowerAdaptor::MachineType() { // handle method call org.ukui.upower.MachineType QString out0; QMetaObject::invokeMethod(parent(), "MachineType", Q_RETURN_ARG(QString, out0)); return out0; } bool UpowerAdaptor::OnBattery() { // handle method call org.ukui.upower.OnBattery bool out0; QMetaObject::invokeMethod(parent(), "OnBattery", Q_RETURN_ARG(bool, out0)); return out0; } double UpowerAdaptor::Percentage() { // handle method call org.ukui.upower.Percentage double out0; QMetaObject::invokeMethod(parent(), "Percentage", Q_RETURN_ARG(double, out0)); return out0; } int UpowerAdaptor::TimeToEmpty() { // handle method call org.ukui.upower.TimeToEmpty int out0; QMetaObject::invokeMethod(parent(), "TimeToEmpty", Q_RETURN_ARG(int, out0)); return out0; } int UpowerAdaptor::TimeToFull() { // handle method call org.ukui.upower.TimeToFull int out0; QMetaObject::invokeMethod(parent(), "TimeToFull", Q_RETURN_ARG(int, out0)); return out0; } QString UpowerAdaptor::UPowerVersion() { // handle method call org.ukui.upower.UPowerVersion QString out0; QMetaObject::invokeMethod(parent(), "UPowerVersion", Q_RETURN_ARG(QString, out0)); return out0; } ukui-power-manager/COPYING0000664000175000017500000001674415167661430014277 0ustar fengfeng GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. ukui-power-manager/ukui-power-manager/0000775000175000017500000000000015167661430016747 5ustar fengfengukui-power-manager/ukui-power-manager/src/0000775000175000017500000000000015167661430017536 5ustar fengfengukui-power-manager/ukui-power-manager/src/brightness.cpp0000664000175000017500000000026315167661430022413 0ustar fengfeng#include "brightness.h" #include "error.h" Brightness::Brightness(QObject *parent) : QObject(parent) { qDebug() << "Brightness" << SUCCESS; } Brightness::~Brightness() { } ukui-power-manager/ukui-power-manager/src/config.h0000664000175000017500000000135515167661430021160 0ustar fengfeng#ifndef CONFIG_H #define CONFIG_H #include #include #include #include "common.h" class QGSettings; class Config : public QObject { Q_OBJECT public: explicit Config(QObject *parent = Q_NULLPTR); ~Config(); void setGsettings(const QString &key, const QVariant &value); QVariant getGsettings(const QString &key); private: bool isNeedConfig(); void initConfig(); QString getProduct(); int getManufacturer(); int vendorTypeMatch(const QString &type); void vendorSpecialTreatment(); QPointer m_gsettings; bool m_isSpecial; QMap m_specialData; enum vendor { Unknown = 0, Greatwall, }; }; #endif // CONFIG_H ukui-power-manager/ukui-power-manager/src/lowbattery.cpp0000664000175000017500000000021315167661430022432 0ustar fengfeng#include "lowbattery.h" #include "error.h" LowBattery::LowBattery(QObject *parent) : QObject(parent) { } LowBattery::~LowBattery() { } ukui-power-manager/ukui-power-manager/src/config.cpp0000664000175000017500000000622215167661430021511 0ustar fengfeng#include #include #include "config.h" #include "error.h" #include "brightness.h" Config::Config(QObject *parent) : QObject(parent), m_gsettings(new QGSettings((QByteArray)POWER_MANAGER_SETTINGS)) { if (isNeedConfig()) { initConfig(); } } Config::~Config() {} void Config::setGsettings(const QString &key, const QVariant &value) { m_gsettings->set(key,value); } QVariant Config::getGsettings(const QString &key) { return m_gsettings->get(key);; } bool Config::isNeedConfig() { if (m_gsettings->get(INIT_POWER_MANAGER).toBool()) { qDebug() << "power manager need init config"; return true; } else { qDebug() << "power manager need't init config"; return false; } } void Config::initConfig() { int ret(0); QStringList str; QString proName; QSettings Settings("/etc/ukui/power/power-manager.conf", QSettings::NativeFormat); if (Settings.status() != QSettings::NoError) { ret = CONFIG_QSET_INIT_ERROR; qCritical() << "error code: " << ret; return; } proName = getProduct(); Settings.beginGroup("product"); str = Settings.childKeys(); Settings.endGroup(); if (-1 == str.indexOf(proName)) { qDebug() << "vendor special treatment"; vendorSpecialTreatment(); } else { qDebug() << "produce special treatement"; Settings.beginGroup(proName); str = Settings.childKeys(); for (int var = 0; var < str.size(); ++var) { setGsettings(str.at(var), Settings.value(str.at(var))); } Settings.endGroup(); } qDebug() << "Config" << SUCCESS; } QString Config::getProduct() { int ret(0); QString name("null"); QFile file("/sys/class/dmi/id/product_name"); if (!file.open(QIODevice::ReadOnly)) { ret = CONFIG_GET_CONF_DATA_ERROR; qCritical() << "error code: " << ret << ", msg: " << file.errorString(); return name; } QByteArray data = file.readAll(); file.close(); name.prepend(data); name = name.simplified(); qDebug() << "product name is :" << name; return name; } int Config::getManufacturer() { int ret(0); QString vendor; QFile file("/sys/class/dmi/id/board_vendor"); if (!file.open(QIODevice::ReadOnly)) { ret = CONFIG_VENDOR_GET_ERROR; qCritical() << "error code: " << ret << ", msg: " << file.errorString(); return Unknown; } QByteArray data = file.readAll(); file.close(); if (data.isEmpty()) { ret = CONFIG_GET_CONF_DATA_ERROR; qCritical() << "error code: " << ret; return Unknown; } vendor.prepend(data); vendor = vendor.simplified(); return vendorTypeMatch(vendor); } int Config::vendorTypeMatch(const QString &type) { int vendor; if (QString("Greatwall") == type) { vendor = Greatwall; } else { vendor = Unknown; } qDebug() << "Manufacturer is :" << vendor; return vendor; } void Config::vendorSpecialTreatment() { switch (getManufacturer()) { case Greatwall: setGsettings(POWER_POLICY_BATTERY, 1); break; default: break; } } ukui-power-manager/ukui-power-manager/src/powermanagercontrol.cpp0000664000175000017500000000024515167661430024333 0ustar fengfeng#include "powermanagercontrol.h" PowerManagerControl::PowerManagerControl(QObject *parent) : QObject(parent) { } PowerManagerControl::~PowerManagerControl() { } ukui-power-manager/ukui-power-manager/src/common.h0000664000175000017500000001007215167661430021177 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COMMON_H #define COMMON_H //Qt #include #include #include //gsettings 配置 #define POWER_MANAGER_SETTINGS "org.ukui.power-manager" //#define SLEEP_COMPUTER_BAT_KEY "sleepComputerBattery" #define INIT_POWER_MANAGER "initPowerManager" //电源管理初始化状态 #define SLEEP_DISPLAY_AC_KEY "sleepDisplayAc" #define SLEEP_DISPLAY_BAT_KEY "sleepDisplayBattery" //空闲关闭显示器 #define SLEEP_COMPUTER_AC "sleepComputerAc" #define SLEEP_COMPUTER_BATTERY "sleepComputerBattery" //空闲随睡 #define LOCK_BLANK_SCREEN "lockBlankScreen" #define IDLE_DIM_TIME "idleDimTime" #define BRIGHTNESS_AC "brightnessAc" //亮度值 #define BRIGHTNESS_BATTERY "brightnessBattery" #define BUTTON_LID_AC "buttonLidAc" //盒盖事件触发操作 #define BUTTON_LID_BATTERY "buttonLidBattery" #define POWER_POLICY_AC "powerPolicyAc" //电源策略(0:性能 1:平衡 2:节能) #define POWER_POLICY_BATTERY "powerPolicyBattery" #define ON_BATTERY_AUTO_SAVE "onBatteryAutoSave" //电池自动开启节能模式 #define LOW_BATTERY_ATUO_SAVE "lowBatteryAutoSave" //低电量时自动开启节能模式 #define PERCENTAGE_LOW "percentageLow" //低电量百分百通知 #define PERCENTAGE_ACTION "percentageAction" //极低电量 #define ACTION_CRITICAL_BATTERY "actionCriticalBattery" //极低电量时执行 //dbus 配置 #define GNOME_SESSION_MANAGER "org.gnome.SessionManager.Presence" #define SESSION_MANAGER_PATH "/org/gnome/SessionManager/Presence" #define POWER_MANAGEMENT_SERVICE "org.ukui.powermanagement" #define POWER_MANAGEMENT_PATH "/" #define POWER_MANAGEMENT_INTERFACE_NAME "org.ukui.powermanagement.interface" #define FREEDESKTOP_UPOWER "org.freedesktop.DBus.Properties" #define UKUI_UPOWER_SERVICE "org.ukui.upower" #define UKUI_UPOWER_PATH "/upower" #define UKUI_UPOWER_BATTERY_PATH "/upower/BatteryInfo" #define UKUI_UPOWER_INTERFACE "org.ukui.upower" #define UKUI_UPOWER_BATTERY_INTERFACE "org.ukui.upower.battery" #define UPOWER_SERVICE "org.freedesktop.UPower" #define UPOWER_PATH "/org/freedesktop/UPower" #define UPOWER_INTERFACE "org.freedesktop.UPower" #define UPOWER_DISPLAY_PATH "/org/freedesktop/UPower/devices/DisplayDevice" #define LOGIN1_SERVICE "org.freedesktop.login1" #define LOGIN1_PATH "/org/freedesktop/login1" #define LOGIN1_MANAGER "org.freedesktop.login1.Manager" //电源管理dbus接口 #define CPU_FREQENCY_MODULATION "CpuFreqencyModulation" #define GET_BRIGHTNESS "GetBrightness" #define GET_MAX_BRIGHTNESS "GetMaxBrightness" #define GPU_FREQENCY_MODULATION "GpuFreqencyModulation" #define HIBERNATE "Hibernate" #define LOCK_SCREEN "LockScreen" #define POWER_OFF "PowerOff" #define REBOOT "Reboot" #define REGULATE_BRIGHTNESS "RegulateBrightness" #define SUSPEND "Suspend" #define TURN_OFF_DISPLAY "TurnOffDisplay" #define EXIT_SERVICE "ExitService" #endif // COMMON_H ukui-power-manager/ukui-power-manager/src/powermanagercenter.cpp0000664000175000017500000000064115167661430024133 0ustar fengfeng#include "powermanagercenter.h" #include "config.h" #include "brightness.h" #include "idle.h" #include "lowbattery.h" #include "powermanagercontrol.h" #include "powerpolicy.h" #include "error.h" PowerManagerCenter::PowerManagerCenter() : m_config(new Config) { initPowerManagerCenter(); } PowerManagerCenter::~PowerManagerCenter() {} int PowerManagerCenter::initPowerManagerCenter() { return 1; } ukui-power-manager/ukui-power-manager/src/main.cpp0000664000175000017500000000131315167661430021164 0ustar fengfeng#include "powermanagercenter.h" #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); // initUkuiLog4qt("ukui-power-manager"); QTranslator translator; if (translator.load(QLocale(), "ukui-power-manager", "_", QM_FILES_INSTALL_PATH)) { a.installTranslator(&translator); } else { qDebug() << "load ukui-power-manager-tray qm file error"; } if (! QDBusConnection::sessionBus().registerService(QString("org.ukui.ukui-power-manager"))) { qCritical() << "ukui-power-manager has been activated"; return 1; } else { PowerManagerCenter powermanagercenter; return a.exec(); } } ukui-power-manager/ukui-power-manager/src/lowbattery.h0000664000175000017500000000032415167661430022102 0ustar fengfeng#ifndef LOWBATTERY_H #define LOWBATTERY_H #include "common.h" class LowBattery : public QObject { Q_OBJECT public: LowBattery(QObject *parent = Q_NULLPTR); ~LowBattery(); }; #endif // LOWBATTERY_H ukui-power-manager/ukui-power-manager/src/idle.h0000664000175000017500000000026015167661430020622 0ustar fengfeng#ifndef IDLE_H #define IDLE_H #include "common.h" class Idle : public QObject { Q_OBJECT public: Idle(QObject *parent = Q_NULLPTR); ~Idle(); }; #endif // IDLE_H ukui-power-manager/ukui-power-manager/src/powermanagercontrol.h0000664000175000017500000000041215167661430023774 0ustar fengfeng#ifndef POWERMANAGERCONTROL_H #define POWERMANAGERCONTROL_H #include "common.h" class PowerManagerControl : public QObject { Q_OBJECT public: PowerManagerControl(QObject *parent = Q_NULLPTR); ~PowerManagerControl(); }; #endif // POWERMANAGERCONTROL_H ukui-power-manager/ukui-power-manager/src/lid.cpp0000664000175000017500000000444215167661430021016 0ustar fengfeng#include "lid.h" #include "error.h" Lid::Lid(QObject *parent) : QObject(parent) { qDebug() << "Lid init start"; inhibitSystemdLogin(); initLidConnection(); m_lidIsClosed = readLidState(); } Lid::~Lid() {} int Lid::inhibitSystemdLogin() { int ret(0); QDBusInterface manager( QStringLiteral(LOGIN1_SERVICE), QStringLiteral(LOGIN1_PATH), QStringLiteral(LOGIN1_MANAGER), QDBusConnection::systemBus()); QDBusReply reply = manager.call( QStringLiteral("Inhibit"), QStringLiteral("handle-lid-switch"), QStringLiteral("powermanagment"), QStringLiteral("ukui-powermanagement blocked LidSwitch!"), QStringLiteral("block")); if (reply.isValid()) { logindLock = reply.value(); qDebug() << "Inhibit got:" << logindLock.fileDescriptor(); } else { ret = INIT_LID_ERROR; qCritical() << "error code: " << ret << ", msg: " << reply.error(); } return ret; } int Lid::initLidConnection() { int ret(0); bool result = QDBusConnection::systemBus().connect( LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_MANAGER, "PrepareForSleep", this, SLOT(dealWakeUpSignal(bool))); if (!result) { ret = LID_CREATE_LOGIN1_CONNECTION_ERROR; qCritical() << "error code: " << ret; } result = QDBusConnection::sessionBus().connect( UKUI_UPOWER_SERVICE, UKUI_UPOWER_PATH, UKUI_UPOWER_INTERFACE, "LidState", this, SLOT(dealLidWatcherMssage(bool))); if (!result) { ret = LID_CREATE_UPOWER_CONNECTION_ERROR; qCritical() << "error code: " << ret; } return ret; } bool Lid::readLidState() { QDBusInterface iface(UPOWER_SERVICE, UPOWER_PATH, UPOWER_INTERFACE, QDBusConnection::systemBus()); return iface.property("LidIsClosed").toBool(); } void Lid::dealLidWatcherMssage(bool isClosed) { qDebug() << "lid watcher, lid is closed:" << isClosed; m_lidIsClosed = isClosed; emit lidChanged(m_lidIsClosed); } void Lid::dealWakeUpSignal(bool isWakeup) { qDebug() << "wake up , system wake up state:" << isWakeup; if (isWakeup) { return; } if (m_lidIsClosed) { qWarning() << "Sleep is awakened unexpectedly!"; lidChanged(m_lidIsClosed); } } ukui-power-manager/ukui-power-manager/src/idle.cpp0000664000175000017500000000015515167661430021160 0ustar fengfeng#include "idle.h" #include "error.h" Idle::Idle(QObject *parent) : QObject(parent) { } Idle::~Idle() {} ukui-power-manager/ukui-power-manager/src/powermanagercenter.h0000664000175000017500000000123315167661430023576 0ustar fengfeng#ifndef POWERMANAGERCENTER_H #define POWERMANAGERCENTER_H #include "common.h" class Config; class Brightness; class Lid; class Idle; class PowerPolicy; class PowerManagerControl; class LowBattery; class PowerManagerCenter : public QObject { Q_OBJECT public: PowerManagerCenter(); virtual ~PowerManagerCenter(); private: int initPowerManagerCenter(); QPointer m_config; QPointer m_brightness; QPointer m_lid; QPointer m_idle; QPointer m_powerPolicy; QPointer m_control; QPointer m_lowBattery; private slots: }; #endif // POWERMANAGERCENTER_H ukui-power-manager/ukui-power-manager/src/brightness.h0000664000175000017500000000033615167661430022061 0ustar fengfeng#ifndef BRIGHTNESS_H #define BRIGHTNESS_H #include "common.h" class Brightness : public QObject { Q_OBJECT public: explicit Brightness(QObject *parent = Q_NULLPTR); ~Brightness(); }; #endif // BRIGHTNESS_H ukui-power-manager/ukui-power-manager/src/powerpolicy.cpp0000664000175000017500000000022015167661430022610 0ustar fengfeng#include "powerpolicy.h" #include "error.h" PowerPolicy::PowerPolicy(QObject *parent) : QObject(parent) { } PowerPolicy::~PowerPolicy() { } ukui-power-manager/ukui-power-manager/src/error.h0000664000175000017500000000163315167661430021043 0ustar fengfeng#ifndef ERROR_H #define ERROR_H //Qt #include #define SUCCESS 0 #define INIT_CONFIG_ERROR 100 #define CONFIG_QSET_INIT_ERROR 101 #define CONFIG_PRODUCT_NAME_ERROR 102 #define CONFIG_VENDOR_GET_ERROR 103 #define CONFIG_GET_CONF_DATA_ERROR 104 #define INIT_BRIGHTNESS_ERROR 200 #define INIT_LID_ERROR 300 #define LID_GET_INHIBIT_ERROR 301 #define LID_CREATE_LOGIN1_CONNECTION_ERROR 302 #define LID_CREATE_UPOWER_CONNECTION_ERROR 303 #define INIT_POWER_MANAGER_CONTROL_ERROR 400 #define INIT_IDLE_ERROR 500 #define INIT_LOW_BATTERY_ERROR 600 #define INIT_POWER_POLICY_ERROR 700 #endif // ERROR_H ukui-power-manager/ukui-power-manager/src/powerpolicy.h0000664000175000017500000000033215167661430022261 0ustar fengfeng#ifndef POWERPOLICY_H #define POWERPOLICY_H #include "common.h" class PowerPolicy : public QObject { Q_OBJECT public: PowerPolicy(QObject *parent = Q_NULLPTR); ~PowerPolicy(); }; #endif // POWERPOLICY_H ukui-power-manager/ukui-power-manager/src/lid.h0000664000175000017500000000071615167661430020463 0ustar fengfeng#ifndef LID_H #define LID_H #include "common.h" class Lid : public QObject { Q_OBJECT public: explicit Lid(QObject *parent = Q_NULLPTR); ~Lid(); bool readLidState(); private: int inhibitSystemdLogin(); int initLidConnection(); QDBusUnixFileDescriptor logindLock; bool m_lidIsClosed; private slots: void dealLidWatcherMssage(bool); void dealWakeUpSignal(bool); signals: void lidChanged(bool); }; #endif // LID_H ukui-power-manager/ukui-power-manager/translations/0000775000175000017500000000000015167661430021470 5ustar fengfengukui-power-manager/ukui-power-manager/translations/ukui-power-manager_zh_CN.ts0000664000175000017500000000013715167661430026641 0ustar fengfeng ukui-power-manager/ukui-power-manager/ukui-power-manager.pro0000664000175000017500000000455715167661430023223 0ustar fengfengQT += core gui dbus greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = ukui-power-manager CONFIG += c++11 link_pkgconfig PKGCONFIG += gsettings-qt LIBS += -lukui-log4qt # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 TRANSLATIONS+=\ translations/ukui-power-manager_zh_CN.ts \ QM_FILES_INSTALL_PATH = /usr/share/ukui-power-manager/daemon/translations/ # CONFIG += lrelase not work for qt5.6, add those from lrelease.prf for compatibility qtPrepareTool(QMAKE_LRELEASE, lrelease) lrelease.name = lrelease lrelease.input = TRANSLATIONS lrelease.output = ${QMAKE_FILE_IN_BASE}.qm lrelease.commands = $$QMAKE_LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_OUT} lrelease.CONFIG = no_link QMAKE_EXTRA_COMPILERS += lrelease PRE_TARGETDEPS += compiler_lrelease_make_all for (translation, TRANSLATIONS) { translation = $$basename(translation) QM_FILES += $$OUT_PWD/$$replace(translation, \\..*$, .qm) } qm_files.files = $$QM_FILES qm_files.path = $$QM_FILES_INSTALL_PATH qm_files.CONFIG = no_check_exist INSTALLS += qm_files DEFINES += QM_FILES_INSTALL_PATH='\\"$${QM_FILES_INSTALL_PATH}\\"' SOURCES += \ src/brightness.cpp \ src/config.cpp \ src/idle.cpp \ src/lid.cpp \ src/lowbattery.cpp \ src/main.cpp \ src/powermanagercenter.cpp \ src/powermanagercontrol.cpp \ src/powerpolicy.cpp HEADERS += \ src/brightness.h \ src/config.h \ src/error.h \ src/common.h \ src/idle.h \ src/lid.h \ src/lowbattery.h \ src/powermanagercenter.h \ src/powermanagercontrol.h \ src/powerpolicy.h # Default rules for deployment. qnx: target.path = /tmp/usr/bin else: unix:!android: target.path = /usr/bin !isEmpty(target.path): INSTALLS += target desktop.files += resources/ukui-power-manager.desktop desktop.path = /etc/xdg/autostart/ INSTALLS += desktop ukui-power-manager/.github/0000775000175000017500000000000015167661415014573 5ustar fengfengukui-power-manager/.github/workflows/0000775000175000017500000000000015167661415016630 5ustar fengfengukui-power-manager/.github/workflows/build.yml0000664000175000017500000000660615167661415020462 0ustar fengfengname: Check build on: push: branches: - master pull_request: branches: - master schedule: - cron: '0 0 * * *' jobs: archlinux: name: on Archlinux runs-on: ubuntu-20.04 container: docker.io/library/archlinux:latest steps: - name: Checkout ukui-power-manager source code uses: actions/checkout@v2 - name: Refresh pacman repository run: pacman -Sy - name: Install build dependencies run: pacman -S --noconfirm base-devel qt5-tools dbus-glib gtk3 libgnome-keyring libnotify upower intltool mate-common yelp-tools libxrandr libx11 libxext xorgproto glib2 - name: Configure & Make run: | ./autogen.sh; make -j$(nproc); debian: name: on Debian Sid runs-on: ubuntu-20.04 container: docker.io/library/debian:sid env: DEBIAN_FRONTEND: noninteractive steps: - name: Checkout ukui-power-manager source code uses: actions/checkout@v2 - name: Update apt repository run: apt-get update -y - name: Install build dependcies run: apt-get install -y build-essential qt5-default qttools5-dev-tools debhelper-compat qtbase5-dev intltool libcanberra-gtk3-dev libdbus-glib-1-dev libgcrypt20-dev libglib2.0-dev libgtk-3-dev libnotify-dev libtool-bin libupower-glib-dev libwnck-3-dev libx11-dev libxext-dev libxml-parser-perl libxrandr-dev mate-common pkg-config xmlto yelp-tools libqt5charts5-dev libqt5x11extras5-dev libgsettings-qt-dev - name: Configure & Make run: | ./autogen.sh --without-keyring; make -j$(nproc); fedora: name: on Fedora 32 runs-on: ubuntu-20.04 container: docker.io/library/fedora:32 steps: - name: Checkout ukui-power-manager source code uses: actions/checkout@v2 - name: Install build dependencies run: dnf install -y which gcc gcc-c++ make cmake cmake-rpm-macros autoconf automake intltool rpm-build qt5-rpm-macros gtk3-devel libwnck3-devel qt5-qtbase-devel intltool libcanberra-devel libcanberra-gtk3 glib2-devel dbus-glib-devel libnotify-devel libtool libgcrypt-devel upower-devel libX11-devel libXext-devel libXrandr-devel perl-XML-Parser qt5-qtx11extras-devel gsettings-qt-devel mate-common mate-desktop-devel qt5-qtcharts-devel xmlto yelp-tools libgnome-keyring-devel - name: Configure & Make run: | ln -sf /usr/bin/lrelease-qt5 /usr/bin/lrelease; ln -sf /usr/bin/qmake-qt5 /usr/bin/qmake; ./autogen.sh; make -j$(nproc); ubuntu: name: on Ubuntu 20.04 runs-on: ubuntu-20.04 container: docker.io/library/ubuntu:focal env: DEBIAN_FRONTEND: noninteractive steps: - name: Checkout ukui-power-manager source code uses: actions/checkout@v2 - name: Update apt repository run: apt-get update -y - name: Install build dependcies run: apt-get install -y build-essential qt5-default qttools5-dev-tools debhelper-compat qtbase5-dev intltool libcanberra-gtk3-dev libdbus-glib-1-dev libgcrypt20-dev libglib2.0-dev libgtk-3-dev libnotify-dev libtool-bin libupower-glib-dev libwnck-3-dev libx11-dev libxext-dev libxml-parser-perl libxrandr-dev mate-common pkg-config xmlto yelp-tools libqt5charts5-dev libqt5x11extras5-dev libgsettings-qt-dev - name: Configure & Make run: | ./autogen.sh --without-keyring; make -j$(nproc); ukui-power-manager/PowerManagementDaemon/0000775000175000017500000000000015167661430017445 5ustar fengfengukui-power-manager/PowerManagementDaemon/idle/0000775000175000017500000000000015167661430020362 5ustar fengfengukui-power-manager/PowerManagementDaemon/idle/idlenesswatcher.cpp0000664000175000017500000002625415167661430024263 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "idlenesswatcher.h" IdlenessWatchcer::IdlenessWatchcer() { initBrightness(); m_idleBrightnessPercentage = m_powerManagerGsettings->get(IDLE_BRIGHTNESS).toInt(); if (m_idleBrightnessPercentage >= 50 && m_idleBrightnessPercentage < 100) { m_idleReduceBrightness = true; } m_idlePowerPolicyAuto = m_powerManagerGsettings->get(IDLE_POWER_POLICY_AUTO).toBool(); connect(m_powerManagerGsettings, &QGSettings::changed, this, [=](const QString &key) { if (key == IDLE_BRIGHTNESS) { m_idleBrightnessPercentage = m_powerManagerGsettings->get(IDLE_BRIGHTNESS).toInt(); if (m_idleBrightnessPercentage >= 50 && m_idleBrightnessPercentage < 100) { m_idleReduceBrightness = true; } else { m_idleReduceBrightness = false; } } if (key == IDLE_POWER_POLICY_AUTO) { m_idlePowerPolicyAuto = m_powerManagerGsettings->get(IDLE_POWER_POLICY_AUTO).toBool(); } }); isFirstRunDonotSuspend(); } IdlenessWatchcer::~IdlenessWatchcer() { delete mTurnOffDisplayTimer; delete mReduceBrightnessTimer; delete mSuspendTimer; } void IdlenessWatchcer::initIdleWatcher() { //初始化gsettings,同时读配置文件 initSettingsConnect(); initTimer(); //监听到空闲信号,开始计时,启动timingBegins函数 QDBusConnection::sessionBus().connect( QString(), QString(SESSION_MANAGER_PATH), GNOME_SESSION_MANAGER, "StatusChanged", this, SLOT(timingBegins(quint32))); QDBusConnection::systemBus().connect( "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "PrepareForSleep", this, SLOT(timingStop())); connect(mTurnOffDisplayTimer, &QTimer::timeout, [this] { QProcess process; if (!isDisablePowerOption()) { process.start("ukui-screensaver-command -b idle"); //等待命令执行结束 process.waitForFinished(); turnOffDisplay(); turnOffDisplaySignal(); } mTurnOffDisplayTimer->stop(); }); connect(mReduceBrightnessTimer, &QTimer::timeout, [this] { reduceBrightness(); mReduceBrightnessTimer->stop(); }); connect(mSuspendTimer, &QTimer::timeout, [this] { if (!isDisablePowerOption() && false == m_firstRunDonotSuspend) { suspend(); } mSuspendTimer->stop(); }); //监听到非空闲信号,打断计时 } void IdlenessWatchcer::initSettingsConnect() { readSettings(); connect(m_powerManagerGsettings, &QGSettings::changed, this, [=] { readSettings(); }); } void IdlenessWatchcer::initTimer() { mTurnOffDisplayTimer = new QTimer; mReduceBrightnessTimer = new QTimer; mSuspendTimer = new QTimer; } void IdlenessWatchcer::readSettings() { //读配置文件 mTurnOffDisplayTimeBat = m_powerManagerGsettings->get(SLEEP_DISPLAY_BAT_KEY).toInt(); qDebug() << "mTurnOffDisplayTimeBat" << mTurnOffDisplayTimeBat; mTurnOffDisplayTimeAc = m_powerManagerGsettings->get(SLEEP_DISPLAY_AC_KEY).toInt(); qDebug() << "mTurnOffDisplayTimeAc" << mTurnOffDisplayTimeAc; mSuspendTimeAc = m_powerManagerGsettings->get(SLEEP_COMPUTER_AC).toInt(); qDebug() << "mSuspendTime" << mSuspendTimeAc; mSuspendTimeBat = m_powerManagerGsettings->get(SLEEP_COMPUTER_BATTERY).toInt(); } void IdlenessWatchcer::timingBegins(quint32 time) { qDebug() << "Idle signal received from SessionManager" << time; if (mSessionVersion == time) { startTimer(); idleReduceBrightness(); idleSwitchPowerPolicy(); controlPowerManagement(SYSTEM_IDLE_RESERVE_CPU0, true); } else { timingStop(); recoveryBrightness(); recoveryPowerPolicy(); controlPowerManagement(SYSTEM_IDLE_RESERVE_CPU0, false); } } int IdlenessWatchcer::turnOffDisplayTime() { if (true == getBatteryState()) { qDebug() << "Time to turn off the display in battery state" << mTurnOffDisplayTimeBat; return mTurnOffDisplayTimeBat; } qDebug() << "Time to turn off the display in power state" << mTurnOffDisplayTimeAc; return mTurnOffDisplayTimeAc; } int IdlenessWatchcer::suspendTime() { if (true == getBatteryState()) { qDebug() << "Time to suspend in battery state" << mSuspendTimeBat; return mSuspendTimeBat; } qDebug() << "Time to suspend in power state" << mSuspendTimeAc; return mSuspendTimeAc; } void IdlenessWatchcer::isFirstRunDonotSuspend() { QDBusInterface iface(POWER_MANAGEMENT_SERVICE, POWER_MANAGEMENT_PATH, POWER_MANAGEMENT_INTERFACE_NAME, QDBusConnection::systemBus()); QDBusReply reply = iface.call(FIRST_RUN_DONOT_SUSPEND); if (reply.isValid()) { m_firstRunDonotSuspend = reply.value(); } qInfo() << "first run donot suspend :" << m_firstRunDonotSuspend; } void IdlenessWatchcer::timingStop() { qDebug() << "timing stop"; if (mTurnOffDisplayTimer->isActive()) { mTurnOffDisplayTimer->stop(); } if (mSuspendTimer->isActive()) { mSuspendTimer->stop(); } if (mReduceBrightnessTimer->isActive()) { mReduceBrightnessTimer->stop(); } } void IdlenessWatchcer::startTimer() { int mTurnOffDisplayTime = turnOffDisplayTime() - mSessionTime; int mSuspendTime = suspendTime() - mSessionTime; int mBrightnessTime = -1; if (0 <= mTurnOffDisplayTime) { mTurnOffDisplayTimer->start(mTurnOffDisplayTime * 1000); } else { qDebug() << "TurnOffDisplayTimer not started!"; } if (0 < mSuspendTime) { mSuspendTimer->start(mSuspendTime * 1000); } else { qDebug() << "SuspendTimer not started!"; } // 仅在非FlemingX设备上启动降低亮度定时器 if(!m_isFlemingX) { if (mTurnOffDisplayTime > 0) { if (mSuspendTime > 0 && mSuspendTime < mTurnOffDisplayTime) { mBrightnessTime = mSuspendTime - 10; } else { mBrightnessTime = mTurnOffDisplayTime - 10; } mReduceBrightnessTimer->start(mBrightnessTime * 1000); } else { if (mSuspendTime > 0) { mBrightnessTime = mSuspendTime - 10; mReduceBrightnessTimer->start(mBrightnessTime * 1000); } } qDebug() << "brightness time:" << mBrightnessTime; } } void IdlenessWatchcer::reduceBrightness() { if(m_isFlemingX) { qDebug() << "flemingx机器,不支持关闭显示器前降低亮度"; return; } if (false == m_idleReduceBrightness) { getUserBrightness(); mBrightness = mUserBrightness * 0.7; } else { mBrightness = mBrightness * 0.7; } if(mBrightness == 0) { qWarning()<<"用户亮度被重置为0,进入睡眠和关闭显示器前10s不再调整亮度"; } else { controlPowerManagement(REGULATE_BRIGHTNESS, mBrightness); } qDebug() << "Reduce the brightness before turning off the display." << "the brightness value is:" << mBrightness; } void IdlenessWatchcer::idleReduceBrightness() { if(m_isFlemingX) { qDebug() << "flemingx机器,不支持空闲状态降低亮度"; return; } if (false == m_idleReduceBrightness) { return ; } // 先检查 mMaxBrightness 是否有效 if (mMaxBrightness <= 0) { qWarning() << "mMaxBrightness 无效,重新初始化"; initBrightness(); } getUserBrightness(); if (true == getBatteryState()) { mBrightness = mUserBrightness * m_idleBrightnessPercentage/100; if(mBrightness == 0) { qWarning()<<"用户亮度被重置为0,进入空闲模式不再调整亮度"; } else { controlPowerManagement(REGULATE_BRIGHTNESS, mBrightness); } } else { mBrightness = mUserBrightness; } qDebug() << "The system enters the idle state." << "the brightness value is:" << mBrightness; } void IdlenessWatchcer::recoveryBrightness() { if(m_isFlemingX) { return; } getUserBrightness(); if(mUserBrightness == 0) { qWarning()<<"用户亮度被重置为0,退出空闲模式不再调整亮度"; } else { controlPowerManagement(REGULATE_BRIGHTNESS, mUserBrightness); } } void IdlenessWatchcer::idleSwitchPowerPolicy() { int powerPolicy; if (true == getBatteryState()) { powerPolicy = m_powerManagerGsettings->get(POWER_POLICY_BATTERY).toInt(); } else { powerPolicy = m_powerManagerGsettings->get(POWER_POLICY_AC).toInt(); } if (Balance == powerPolicy) { controlPowerManagement(GPU_FREQENCY_MODULATION, EnergySaving); } if (true == m_idlePowerPolicyAuto) { if (EnergySaving != powerPolicy) { controlPowerManagement(CPU_FREQENCY_MODULATION, EnergySaving); } } } void IdlenessWatchcer::recoveryPowerPolicy() { int powerPolicy; if (true == getBatteryState()) { powerPolicy = m_powerManagerGsettings->get(POWER_POLICY_BATTERY).toInt(); } else { powerPolicy = m_powerManagerGsettings->get(POWER_POLICY_AC).toInt(); } if (Balance == powerPolicy) { controlPowerManagement(GPU_FREQENCY_MODULATION, powerPolicy); } if (true == m_idlePowerPolicyAuto) { if (EnergySaving != powerPolicy) { controlPowerManagement(CPU_FREQENCY_MODULATION, powerPolicy); } } } bool IdlenessWatchcer::getBatteryState() { QDBusInterface iface(UPOWER_SERVICE, UPOWER_PATH, FREEDESKTOP_UPOWER, QDBusConnection::systemBus()); QDBusReply reply = iface.call("Get", "org.freedesktop.UPower", "OnBattery"); if (reply.isValid()) { return reply.value().toBool(); } qDebug() << "The battery status obtained by closing the cover is abnormal!"; return false; } bool IdlenessWatchcer::isDisablePowerOption() { int ret; QDBusInterface gmInter("org.ukui.SettingsDaemon", "/GlobalSignal", "org.ukui.SettingsDaemon.GlobalSignal", QDBusConnection::sessionBus()); if(!gmInter.isValid()) { qDebug()<<"interface is unvalid"; return false; } QDBusReply boolRep = gmInter.call("isHidePoweroffUi"); ret = boolRep.value(); if(ret) { qDebug() << "hide power option.........." ; } return ret; } ukui-power-manager/PowerManagementDaemon/idle/idlenesswatcher.h0000664000175000017500000001025715167661430023724 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef IDLENESSWATCHER_H #define IDLENESSWATCHER_H #include "eventwatcher.h" #include #define CANNOT_SUSPEND 1 /** * @brief The IdlenessWatchcer class * 监听空闲的类 * 空闲后会有三个操作,分别是: * 1.降低屏幕亮度 * 2.关闭显示器 * 3.定时睡眠/休眠 */ class IdlenessWatchcer : public EventWatcher { Q_OBJECT public: IdlenessWatchcer(); ~IdlenessWatchcer(); /** * @brief initIdleWatcher * 初始化空闲监控类 * */ void initIdleWatcher(); bool getBatteryState(); private: /* * =============================================== * 以下为初始化相关成员函数 * =============================================== */ /** * @brief initSettingsConnect * 初始化GSetting并连接 */ void initSettingsConnect(); /** * @brief initTimer * 初始化定时器 */ void initTimer(); /** * @brief turnOffDisplayTime * 关闭显示器时间 * @return */ int turnOffDisplayTime(); /** * @brief suspendTime * 睡眠时间 * @return */ int suspendTime(); /* * =============================================== * 以下为成员变量,包括定时器,亮度值 * =============================================== */ /** * @brief mTurnOffDisplayTimer * 关闭显示器的定时器 */ QTimer *mTurnOffDisplayTimer; /** * @brief mReduceBrightnessTimer * 降低屏幕亮度的定时器 */ QTimer *mReduceBrightnessTimer; /** * @brief mSuspendTimer * 定时休眠/睡眠的定时器 */ QTimer *mSuspendTimer; /** * @brief mTurnOffDisplayTime * mTurnOffDisplayTime 毫秒后关闭显示器(电源情况下) */ int mTurnOffDisplayTimeAc; /** * @brief mTurnOffDisplayTimeBat * mTurnOffDisplayTimeBat毫秒后关闭显示器(电池情况下) */ int mTurnOffDisplayTimeBat; /** * @brief mReduceBrightnessTime * mReduceBrightnessTime毫秒后降低屏幕亮度 */ int mReduceBrightnessTime; /** * @brief mSuspendTimeBat * mSuspendTimeBat毫秒后睡眠(电池状态下) */ int mSuspendTimeBat; /** * @brief mSuspendTimeAc * mSuspendTimeAc毫秒后睡眠(电源状态下) */ int mSuspendTimeAc; /** * @brief mSessionVersion * session版本 */ const quint32 mSessionVersion = 3; /** * @brief mSessionTime * mSessionTime进入空闲时间 */ const int mSessionTime = 60; bool m_idleReduceBrightness = false; int m_idleBrightnessPercentage; bool m_idlePowerPolicyAuto = false; bool m_firstRunDonotSuspend = false; void isFirstRunDonotSuspend(); private slots: /** * @brief readSettings * 读配置文件 */ void readSettings(); /** * @brief timingBegins * 开始计时 */ void timingBegins(quint32); /** * @brief timingStop * 停止计时 */ void timingStop(); void startTimer(); /** * @brief reduceBrightnessTiming * 降低屏幕亮度计时 */ void reduceBrightness(); void idleReduceBrightness(); void recoveryBrightness(); void idleSwitchPowerPolicy(); void recoveryPowerPolicy(); /** * @brief isDisablePowerOption * @return 电源选项是否被禁用。 */ bool isDisablePowerOption(); }; #endif // IDLENESSWATCHER_H ukui-power-manager/PowerManagementDaemon/translations/0000775000175000017500000000000015167661430022166 5ustar fengfengukui-power-manager/PowerManagementDaemon/translations/ukui-power-manager-daemon_zh_HK.ts0000664000175000017500000001120115167661430030574 0ustar fengfeng LowPowerWatcher Low battery notification 低電量消息通知 The system enters a low battery state 系統進入低電量狀態 Very low battery notification 極低電量消息通知 Current power is:%1%. The system will turn off the display in one minute 當前電量為:%1%,系統將於一分鐘後關閉顯示器 Current power is:%1%,The system will suspend in one minute 當前電量為:%1%,系統將於一分鐘後睡眠 Current power is:%1%,The system will shutdown in one minute 當前電量為:%1%,系統將於一分鐘後關機 Current power is:%1%,The system will hibernate in one minute 當前電量為:%1%,系統將於一分鐘後休眠 Power Manager 電源管理員 PowerMsgNotificat error message 错误消息 charge notification 充电通知 battery is charging 电池正在充电 discharged notification 放电通知 battery is discharging 电池正在放电中 full charge notification 充满电通知 battery is full 电池现在已经充满 Charge notification 充電通知 Battery is charging 電池正在充電 Discharged notification 放電通知 Battery is discharging 電池正在放電中 Full charge notification 充滿電通知 Battery is full 電池現在已經充滿 Power Manager 電源管理員 ukui-power-manager/PowerManagementDaemon/translations/ukui-power-manager-daemon_mn.ts0000664000175000017500000001073415167661430030215 0ustar fengfeng LowPowerWatcher Low battery notification The system enters a low battery state Very low battery notification Current power is:%1%. The system will turn off the display in one minute Current power is:%1%,The system will suspend in one minute Current power is:%1%,The system will shutdown in one minute Current power is:%1%,The system will hibernate in one minute Power Manager PowerMsgNotificat error message 错误消息 charge notification 充电通知 battery is charging 电池正在充电 discharged notification 放电通知 battery is discharging 电池正在放电中 full charge notification 充满电通知 battery is full 电池现在已经充满 Charge notification Battery is charging Discharged notification Battery is discharging Full charge notification Battery is full Power Manager ukui-power-manager/PowerManagementDaemon/translations/ukui-power-manager-daemon_bo_CN.ts0000664000175000017500000001377115167661430030567 0ustar fengfeng LowPowerWatcher Low battery notification དམའ་གློག་ཚད་གནས་ཚུལ་བརྡ་སྦྱོར། The system enters a low battery state མ་ལག་སླེབས་པ་དམའ་གློག་ཚད་རྣམ་པ། Very low battery notification ཧ་ཅང་དམའ་བ་བཅས་ཀྱི་གློག་ཚད་གནས་ཚུལ་བརྡ་སྦྱོར། Current power is:%1%. The system will turn off the display in one minute མིག་སྔར་གློག་ཚད་དེ་%1%། མ་ལག་དེ་སྐར་མ་གཅིག་གི་རྗེས་སྒོ་རྒྱག་བརྡ་སྟོན་ཡོ་ཆས། Current power is:%1%,The system will suspend in one minute མིག་སྔར་གློག་ཚད་དེ་%1%། མ་ལག་དེ་སྐར་མ་གཅིག་གི་རྗེས་གཉིད། Current power is:%1%,The system will shutdown in one minute མིག་སྔར་གློག་ཚད་དེ་%1%། མ་ལག་དེ་སྐར་མ་གཅིག་གི་རྗེས་སྒོ་རྒྱག་རྩིས་འཁོར། Current power is:%1%,The system will hibernate in one minute མིག་སྔར་གློག་ཚད་དེ་%1%། མ་ལག་དེ་སྐར་མ་གཅིག་གི་རྗེས་ཉལ། Power Manager གློག་ཁུངས་དོ་དམ་ཆས་ PowerMsgNotificat charge notification གློག་གསོག་པའི་བརྡ་ཐོ། battery is charging གློག་གཡིས་བཞིན་མང་ཙམ། discharged notification གློག་འགྱུ་འི་བརྡ་ཐོ། battery is discharging གློག་གཡིས་བཞིན་གློག་འཁྱུག་པ་ཁྲོད། full charge notification སྐྱེ་སྟོབས་ཀྱི་གློག་འཕྲིན་བརྡ་ཐོ། battery is full གློག་གཡིས་ད་ལྟ་ཁེངས་པ། Charge notification གློག་གསོག་པའི་བརྡ་ཐོ། Battery is charging གློག་གཡིས་བཞིན་མང་ཙམ། Discharged notification གློག་འགྱུ་འི་བརྡ་ཐོ། Battery is discharging གློག་གཡིས་བཞིན་གློག་འཁྱུག་པ་ཁྲོད། Full charge notification སྐྱེ་སྟོབས་ཀྱི་གློག་འཕྲིན་བརྡ་ཐོ། Battery is full གློག་གཡིས་ད་ལྟ་ཁེངས་པ། Power Manager གློག་ཁུངས་དོ་དམ་ཆས་ ukui-power-manager/PowerManagementDaemon/translations/ukui-power-manager-daemon_zh_CN.ts0000664000175000017500000001117715167661430030606 0ustar fengfeng LowPowerWatcher Low battery notification 低电量消息通知 The system enters a low battery state 系统进入低电量状态 Very low battery notification 极低电量消息通知 Current power is:%1%. The system will turn off the display in one minute 当前电量为:%1%,系统将于一分钟后关闭显示器 Current power is:%1%,The system will suspend in one minute 当前电量为:%1%,系统将于一分钟后睡眠 Current power is:%1%,The system will shutdown in one minute 当前电量为:%1%,系统将于一分钟后关机 Current power is:%1%,The system will hibernate in one minute 当前电量为:%1%,系统将于一分钟后休眠 Power Manager 电源管理器 PowerMsgNotificat error message 错误消息 charge notification 充电通知 battery is charging 电池正在充电 discharged notification 放电通知 battery is discharging 电池正在放电中 full charge notification 充满电通知 battery is full 电池现在已经充满 Charge notification 充电通知 Battery is charging 电池正在充电 Discharged notification 放电通知 Battery is discharging 电池正在放电中 Full charge notification 充满电通知 Battery is full 电池现在已经充满 Power Manager 电源管理器 ukui-power-manager/PowerManagementDaemon/translations/ukui-power-manager-daemon_mn_MN.ts0000664000175000017500000001446515167661430030614 0ustar fengfeng LowPowerWatcher Low battery notification ᠳᠣᠤᠷ᠎ᠠ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠤ ᠬᠡᠮᠵᠢᠶ᠎ᠡ ᠶᠢᠨ ᠮᠡᠳᠡᠭᠡ ᠮᠡᠳᠡᠭᠳᠡᠯ The system enters a low battery state ᠰᠢᠰᠲ᠋ᠧᠮ ᠳᠣᠣᠷ᠎ᠠ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠤ ᠬᠡᠮᠵᠢᠶ᠎ᠡ ᠶᠢᠨ ᠪᠠᠶᠢᠳᠠᠯ ᠳᠤ ᠣᠷᠣᠪᠠ᠃ Very low battery notification ᠲᠤᠶᠢᠯ ᠤᠨ ᠳᠣᠣᠷ᠎ᠠ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠮᠡᠳᠡᠭᠡ ᠮᠡᠳᠡᠭᠳᠡᠯ Current power is:%1%. The system will turn off the display in one minute ᠣᠳᠣᠬᠠᠨ ᠤ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠤ ᠬᠡᠮᠵᠢᠶ᠎ᠡ ᠨᠢ ᠄ 1% ᠂ ᠰᠢᠰᠲ᠋ᠧᠮ ᠨᠢ ᠨᠢᠭᠡ ᠮᠢᠨᠦᠢᠲ᠋ ᠦᠨ ᠳᠠᠷᠠᠭ᠎ᠠ ᠳᠡᠯᠭᠡᠴᠡ ᠶᠢ ᠬᠠᠭᠠᠬᠤ ᠪᠣᠯᠣᠨ᠎ᠠ ᠃ Current power is:%1%,The system will suspend in one minute ᠣᠳᠣᠬᠠᠨ ᠳᠤ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠤ ᠬᠡᠮᠵᠢᠶ᠎ᠡ ᠨᠢ ᠄ 1% ᠂ ᠰᠢᠰᠲ᠋ᠧᠮ ᠨᠢ ᠨᠢᠭᠡ ᠮᠢᠨᠦᠢᠲ᠋ ᠦᠨ ᠳᠠᠷᠠᠭ᠎ᠠ ᠤᠨᠲᠠᠬᠤ ᠪᠣᠯᠣᠨ᠎ᠠ ᠃ Current power is:%1%,The system will shutdown in one minute ᠣᠳᠣᠬᠠᠨ ᠳᠤ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠤ ᠬᠡᠮᠵᠢᠶ᠎ᠡ ᠨᠢ ᠄ 1% ᠂ ᠰᠢᠰᠲ᠋ᠧᠮ ᠨᠢ ᠨᠢᠭᠡ ᠮᠢᠨᠦᠢᠲ᠋ ᠦᠨ ᠳᠠᠷᠠᠭ᠎ᠠ ᠬᠠᠭᠠᠭᠳᠠᠨ᠎ᠠ ᠃ Current power is:%1%,The system will hibernate in one minute ᠣᠳᠣᠬᠠᠨ ᠳᠤ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠤ ᠬᠡᠮᠵᠢᠶ᠎ᠡ ᠨᠢ ᠄ 1% ᠂ ᠰᠢᠰᠲ᠋ᠧᠮ ᠨᠢ ᠨᠢᠭᠡ ᠮᠢᠨᠦᠢᠲ᠋ ᠦᠨ ᠳᠠᠷᠠᠭ᠎ᠠ ᠤᠨᠲᠠᠬᠤ ᠪᠣᠯᠣᠨ᠎ᠠ ᠃ Power Manager ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠭᠡᠭᠴᠢ ᠶᠢᠨ ᠬᠠᠮᠢᠶᠠᠷᠤᠯᠲᠠ ᠶᠢᠨ ᠪᠠᠭᠠᠵᠢ᠃ PowerMsgNotificat error message 错误消息 charge notification 充电通知 battery is charging 电池正在充电 discharged notification 放电通知 battery is discharging 电池正在放电中 full charge notification 充满电通知 battery is full 电池现在已经充满 Charge notification ᠴᠠᠬᠢᠯᠭᠠᠨ ᠨᠡᠮᠡᠬᠦ ᠮᠡᠳᠡᠭᠳᠡᠯ Battery is charging ᠳ᠋ᠢᠶᠠᠨ ᠢ ᠣᠳᠣ ᠶᠠᠭ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠨᠡᠮᠡᠵᠦ ᠪᠠᠢ᠌ᠨ᠎ᠠ ᠃ Discharged notification ᠴᠠᠬᠢᠯᠭᠠᠨ ᠭᠠᠷᠭᠠᠬᠤ ᠮᠡᠳᠡᠭᠳᠡᠯ ᠃ Battery is discharging ᠳ᠋ᠢᠶᠠᠨ ᠢ ᠣᠳᠣ ᠶᠠᠭ ᠴᠠᠬᠢᠯᠭᠠᠨ ᠭᠠᠷᠭᠠᠵᠤ ᠪᠠᠢ᠌ᠨ᠎ᠠ ᠃ Full charge notification ᠴᠠᠬᠢᠯᠭᠠᠨ ᠨᠡᠮᠡᠬᠦ ᠮᠡᠳᠡᠭᠳᠡᠯ ᠪᠢᠯᠬᠠᠮ᠎ᠠ ᠃ Battery is full ᠳ᠋ᠢᠶᠠᠨ ᠢ ᠣᠳᠣ ᠨᠢᠭᠡᠨᠲᠡ ᠳᠦᠭᠦᠷᠴᠡᠢ ᠃ Power Manager ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠭᠡᠭᠴᠢ ᠶᠢᠨ ᠬᠠᠮᠢᠶᠠᠷᠤᠯᠲᠠ ᠶᠢᠨ ᠪᠠᠭᠠᠵᠢ᠃ ukui-power-manager/PowerManagementDaemon/translations/ukui-power-manager-daemon_tr.ts0000664000175000017500000000677215167661430030237 0ustar fengfeng LowPowerWatcher Low battery notification The system enters a low battery state Very low battery notification Current power is:%1%. The system will turn off the display in one minute Current power is:%1%,The system will suspend in one minute Current power is:%1%,The system will shutdown in one minute Current power is:%1%,The system will hibernate in one minute Power Manager PowerMsgNotificat Charge notification Battery is charging Discharged notification Battery is discharging Full charge notification Battery is full Power Manager ukui-power-manager/PowerManagementDaemon/cloudplatform.h0000664000175000017500000000207015167661430022470 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef CLOUDPLATFORM_H #define CLOUDPLATFORM_H #include #include class CloudPlatform : public QObject { Q_OBJECT public: explicit CloudPlatform(QObject *parent = nullptr); static CloudPlatform* self(); private: bool m_isCloudPlatform = false; public: bool isCloudPlatform(); signals: }; #endif // CLOUDPLATFORM_H ukui-power-manager/PowerManagementDaemon/PowerManagementDaemon.pro0000664000175000017500000001033215167661430024403 0ustar fengfengQT += core gui dbus network greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = ukui-powermanagement CONFIG += c++11 link_pkgconfig PKGCONFIG += gsettings-qt6 kysdk-sysinfo LIBS += -lukui-log4qt INCLUDEPATH += $$PWD/../shared/include # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 TRANSLATIONS+=\ translations/ukui-power-manager-daemon_bo_CN.ts \ translations/ukui-power-manager-daemon_zh_CN.ts \ translations/ukui-power-manager-daemon_tr.ts \ translations/ukui-power-manager-daemon_mn.ts \ translations/ukui-power-manager-daemon_mn_MN.ts \ translations/ukui-power-manager-daemon_zh_HK.ts QM_FILES_INSTALL_PATH = /usr/share/ukui-power-manager/daemon/translations/ # CONFIG += lrelase not work for qt5.6, add those from lrelease.prf for compatibility qtPrepareTool(QMAKE_LRELEASE, lrelease) lrelease.name = lrelease lrelease.input = TRANSLATIONS lrelease.output = ${QMAKE_FILE_IN_BASE}.qm lrelease.commands = $$QMAKE_LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_OUT} lrelease.CONFIG = no_link QMAKE_EXTRA_COMPILERS += lrelease PRE_TARGETDEPS += compiler_lrelease_make_all for (translation, TRANSLATIONS) { translation = $$basename(translation) QM_FILES += $$OUT_PWD/$$replace(translation, \\..*$, .qm) } qm_files.files = $$QM_FILES qm_files.path = $$QM_FILES_INSTALL_PATH qm_files.CONFIG = no_check_exist INSTALLS += qm_files DEFINES += QM_FILES_INSTALL_PATH='\\"$${QM_FILES_INSTALL_PATH}\\"' SOURCES += \ acwatcher/acwatcher.cpp \ cloudplatform.cpp \ eventwatcher.cpp \ globalconfig.cpp \ gsettingwatcher/gsettingwatcher.cpp \ hardware/huawei/flemingx.cpp \ lowpowerwatcher/lowpowerwatcher.cpp \ main.cpp \ powermanagementdamon.cpp \ idle/idlenesswatcher.cpp \ lidwatcher/lidwatcher.cpp \ ukui-power-test-tool/upower-dbus/upm_upowerdbus.cpp \ ukui-power-test-tool/upower-dbus/upowerbatterydbus.cpp \ ukui-power-test-tool/upower-dbus/upowerdbus.cpp \ ukui-power-test-tool/upower-dbus/upowerlinepowerdbus.cpp \ ukui-power-test-tool/uptt-gsettings/upm_gsettings.cpp \ ukui-power-test-tool/upttbatterydate.cpp \ ukui-power-test-tool/upttbrightnessconfig.cpp \ ukui-power-test-tool/upttcpupolicyconfig.cpp \ ukui-power-test-tool/upttruntestbutton.cpp \ ukui-power-test-tool/uptttestconfigpage.cpp \ upmcustomdefaultgsettings.cpp \ upmexternalinterface.cpp HEADERS += \ acwatcher/acwatcher.h \ cloudplatform.h \ eventwatcher.h \ globalconfig.h \ gsettingwatcher/gsettingwatcher.h \ hardware/huawei/flemingx.h \ lowpowerwatcher/lowpowerwatcher.h \ powermanagementdamon.h \ idle/idlenesswatcher.h \ lidwatcher/lidwatcher.h \ common.h \ ukui-power-test-tool/upower-dbus/upm_upowerdbus.h \ ukui-power-test-tool/upower-dbus/upowerbatterydbus.h \ ukui-power-test-tool/upower-dbus/upowerdbus.h \ ukui-power-test-tool/upower-dbus/upowerlinepowerdbus.h \ ukui-power-test-tool/uptt-gsettings/upm_gsettings.h \ ukui-power-test-tool/upttbatterydate.h \ ukui-power-test-tool/upttbrightnessconfig.h \ ukui-power-test-tool/upttcpupolicyconfig.h \ ukui-power-test-tool/upttruntestbutton.h \ ukui-power-test-tool/uptttestconfigpage.h \ upmcustomdefaultgsettings.h \ upmexternalinterface.h # Default rules for deployment. qnx: target.path = /tmp/usr/bin else: unix:!android: target.path = /usr/bin !isEmpty(target.path): INSTALLS += target desktop.files += resources/ukui-powermanagement-daemon.desktop desktop.path = /etc/xdg/autostart/ upmGsettingsGlobalConf.files += resources/upm-gsettings-global.conf upmGsettingsGlobalConf.path = /usr/share/ukui/ukui-power-manager/ INSTALLS += desktop upmGsettingsGlobalConf ukui-power-manager/PowerManagementDaemon/resources/0000775000175000017500000000000015167661430021457 5ustar fengfengukui-power-manager/PowerManagementDaemon/resources/upm-gsettings-global.conf0000664000175000017500000000035615167661430026376 0ustar fengfeng[default-policy-ac] balanceModeBoardName = ":rnNL203B:,:rnEM_KX_819_V20_D:" powersaveModeBoardName = "" [default-policy-battery] balanceModeBoardName = ":rnNL203B:,:rnEM_KX_819_V20_D:" powersaveModeBoardName = ":rnToBesyncedwithFRU:" ukui-power-manager/PowerManagementDaemon/resources/ukui-powermanagement-daemon.desktop0000664000175000017500000000145315167661430030462 0ustar fengfeng[Desktop Entry] Name=Power Manager Name[zh_CN]=电源管理器 Name[bo_CN]=གློག་ཁུངས་དོ་དམ་ཆས་ Name[zh_HK]=電源管理器 Name[mn]=ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠭᠡᠭᠴᠢ ᠶᠢᠨ ᠬᠠᠮᠢᠶᠠᠷᠤᠯᠲᠠ ᠶᠢᠨ ᠪᠠᠭᠠᠵᠢ᠃ Comment=Power management daemon Comment[zh_CN]=电源管理守护程序 Comment[bo_CN]=གློག་ཁུངས་དོ་དམ་ཆས་ Comment[zh_CN]=電源管理守護程式 Comment[mn]=ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠭᠡᠭᠴᠢ ᠶᠢᠨ ᠬᠠᠮᠢᠶᠠᠷᠴᠤ ᠬᠠᠮᠠᠭᠠᠯᠠᠬᠤ ᠳᠡᠰ ᠳᠠᠷᠠᠭᠠᠯᠠᠯ᠃ Icon=ukui-power-manager Exec=ukui-powermanagement Terminal=false Type=Application NoDisplay=true Categories= OnlyShowIn=UKUI; X-UKUI-AutoRestart=true ukui-power-manager/PowerManagementDaemon/acwatcher/0000775000175000017500000000000015167661430021406 5ustar fengfengukui-power-manager/PowerManagementDaemon/acwatcher/acwatcher.h0000664000175000017500000000267115167661430023526 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ACWATCHER_H #define ACWATCHER_H #include "eventwatcher.h" class AcWatcher : public EventWatcher { Q_OBJECT public: AcWatcher(); ~AcWatcher(){ } /** * @brief initAcWatcher * 初始化电源插拔 */ void initAcWatcher(); /** * @brief readOnBattery * 获取电源状态(AC或者battery) * @return */ bool readOnBattery(); bool &mPowerState = mOnBattery; signals: /** * @brief acChanged * 电源状态改变信号 */ void acChanged(bool); private: bool hasBattery(); private slots: /** * @brief dealAcWatcherMssage * 处理电源插拔消息 */ void dealAcWatcherMssage(void); private: bool mOnBattery; }; #endif // ACWATCHER_H ukui-power-manager/PowerManagementDaemon/acwatcher/acwatcher.cpp0000664000175000017500000000526015167661430024056 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "acwatcher.h" #include "dmi_chassis_type.h" // #include // using namespace kdk; AcWatcher::AcWatcher():mOnBattery(false) { } void AcWatcher::initAcWatcher() { if (hasBattery()) { QDBusConnection::systemBus().connect( UPOWER_SERVICE, UPOWER_PATH, FREEDESKTOP_UPOWER, "PropertiesChanged", this, SLOT(dealAcWatcherMssage(void))); mOnBattery = readOnBattery(); } } void AcWatcher::dealAcWatcherMssage() { bool value; value = readOnBattery(); if (mOnBattery != value) { mOnBattery = value; emit acChanged(mOnBattery); qDebug() << "Power status change signal transmission"; // if (false == mOnBattery) { // kdk::KSoundEffects::playSound(POWER_PLUG); // } } } bool AcWatcher::readOnBattery() { QDBusInterface iface(UPOWER_SERVICE, UPOWER_PATH, FREEDESKTOP_UPOWER, QDBusConnection::systemBus()); QDBusReply reply = iface.call("Get", "org.freedesktop.UPower", "OnBattery"); if (reply.isValid()) { return reply.value().toBool(); } qDebug() << "OnBattery error!"; return false; } bool AcWatcher::hasBattery() { QFile file("/sys/class/dmi/id/chassis_type"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "Failed to open chassis_type file"; return false; } QString chassisTypeStr = file.readAll().trimmed(); file.close(); bool ok = false; int chassisTypeInt = chassisTypeStr.toInt(&ok); if (!ok) { qWarning() << "Invalid chassis_type format:" << chassisTypeStr; return false; } switch (static_cast(chassisTypeInt)) { case DmiChassisType::Laptop: case DmiChassisType::Convertible: case DmiChassisType::Detachable: case DmiChassisType::Tablet: return true; default: qDebug() << "Device type not supported for battery:" << chassisTypeInt; return false; } } ukui-power-manager/PowerManagementDaemon/common.h0000664000175000017500000001225015167661430021106 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COMMON_H #define COMMON_H //Qt #include #include #include #include //gsettings 配置 #define POWER_MANAGER_SETTINGS "org.ukui.power-manager" #define SCREEN_SAVER_SETTINGS "org.ukui.screensaver" #define SLEEP_DISPLAY_AC_KEY "sleepDisplayAc" #define SLEEP_DISPLAY_BAT_KEY "sleepDisplayBattery" //空闲关闭显示器 #define SLEEP_COMPUTER_AC "sleepComputerAc" #define SLEEP_COMPUTER_BATTERY "sleepComputerBattery" //空闲随睡 #define BUTTON_POWER_BATTERY "buttonPower" //电源按钮按下执行 "suspend" "shutdown" "interactive" #define IDLE_BRIGHTNESS "idleBrightness" //空闲状态亮度,降低到当前亮度的 #define IDLE_POWER_POLICY_AUTO "idlePowerPolicyAuto" //空闲时切换电源策略 constexpr const char* HIBERNATE_COMPUTER_AC_KEY = "hibernateComputerAc"; #define SLEEPACTIVATIONENABLED "sleepActivationEnabled" #define CLOSEACTIVATIONENABLED "closeActivationEnabled" #define BRIGHTNESS_AC "brightnessAc" //亮度值 #define BRIGHTNESS_BATTERY "brightnessBattery" #define BRIGHTNESS_ENHANCEMENT_SWITCH "brightnessEnhancementSwitch" #define BUTTON_LID_AC "buttonLidAc" //盒盖事件触发操作 #define BUTTON_LID_BATTERY "buttonLidBattery" #define POWER_POLICY_AC "powerPolicyAc" //电源策略(0:性能 1:平衡 2:节能) #define POWER_POLICY_BATTERY "powerPolicyBattery" #define POWER_POLICY_CURRENT "powerPolicyCurrent" #define POWER_POLICY_BATTERY_BACKUP "powerPolicyBatteryBackup" #define POWER_POLICY_AUTO "powerPolicyAuto" #define ON_BATTERY_AUTO_SAVE "onBatteryAutoSave" //电池自动开启节能模式 #define LOW_BATTERY_ATUO_SAVE "lowBatteryAutoSave" //低电量时自动开启节能模式 #define PERCENTAGE_LOW "percentageLow" //低电量百分百通知 #define PERCENTAGE_ACTION "percentageAction" //极低电量 #define ACTION_CRITICAL_BATTERY "actionCriticalBattery" //极低电量时执行 #define PERCENT_LOW_REDUCE_BRIGHTNESS "percentageLowReduceBrightness" #define PRE_POWER_MODE "preprocessPowerMode" //dbus 配置 #define GNOME_SESSION_MANAGER "org.gnome.SessionManager.Presence" #define SESSION_MANAGER_PATH "/org/gnome/SessionManager/Presence" #define POWER_MANAGEMENT_SERVICE "org.ukui.powermanagement" #define POWER_MANAGEMENT_PATH "/" #define POWER_MANAGEMENT_INTERFACE_NAME "org.ukui.powermanagement.interface" #define FREEDESKTOP_UPOWER "org.freedesktop.DBus.Properties" #define UKUI_UPOWER_PATH "/upower" #define UKUI_UPOWER_SERVICE "org.ukui.upower" #define UKUI_UPOWER_INTERFACE "org.ukui.upower" #define UKUI_UPOWER_BATTERY_PATH "/upower/BatteryInfo" #define UKUI_UPOWER_BATTERY_INTERFACE "org.ukui.upower.battery" #define UPOWER_PATH "/org/freedesktop/UPower" #define UPOWER_SERVICE "org.freedesktop.UPower" #define UPOWER_DISPLAY_PATH "/org/freedesktop/UPower/devices/DisplayDevice" //电源管理dbus接口 #define CPU_FREQENCY_MODULATION "CpuFreqencyModulation" #define GET_BRIGHTNESS "GetBrightness" #define GET_MAX_BRIGHTNESS "GetMaxBrightness" #define GPU_FREQENCY_MODULATION "GpuFreqencyModulation" #define SET_PCIE_ASPM_MODE "SetPcieAspmMode" #define SET_AUDIO_MODE "SetAudioMode" #define REGULATE_BRIGHTNESS "RegulateBrightness" #define IS_BRIGHTNESS_ENHANCEMENT_SUPPORTED "IsBrightnessEnhancementSupported" const double BRIGHTNESS_ENHANCEMENT_THRESHOLD_PERCENT = 0.7; const double BRIGHTNESS_ENHANCEMENT_MAX_PERCENT_150 = 150.0; #define SYSTEM_IDLE_RESERVE_CPU0 "SystemIdleReserveCpu0" #define ENTER_TLP "enterTlp" #define EXIT_TLP "exitTlp" #define TLP_TIMER 3500 #define SUSPEND "Suspend" #define TURN_OFF_DISPLAY "TurnOffDisplay" #define EXIT_SERVICE "ExitService" #define FIRST_RUN_DONOT_SUSPEND "FirstRunDonotSuspend" /** * UpDeviceState: * * The device state. **/ typedef enum { UP_DEVICE_STATE_UNKNOWN, UP_DEVICE_STATE_CHARGING, UP_DEVICE_STATE_DISCHARGING, UP_DEVICE_STATE_EMPTY, UP_DEVICE_STATE_FULLY_CHARGED, UP_DEVICE_STATE_PENDING_CHARGE, UP_DEVICE_STATE_PENDING_DISCHARGE, UP_DEVICE_STATE_LAST } UpDeviceState; #endif // COMMON_H ukui-power-manager/PowerManagementDaemon/powermanagercenter.cpp0000664000175000017500000000011715167661430024040 0ustar fengfeng#include "powermanagercenter.h" powermanagercenter::powermanagercenter() { } ukui-power-manager/PowerManagementDaemon/eventwatcher.h0000664000175000017500000001101015167661430022306 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef EVENTWATCHER_H #define EVENTWATCHER_H #include #include #include #include #include "common.h" #include "globalconfig.h" #include "hardware/huawei/flemingx.h" #define LOGIN1_DBUS_SET_POWEROFF "PowerOff" #define LOGIN1_DBUS_SET_SUSPEND "Suspend" #define LOGIN1_DBUS_SET_HIBERNATE "Hibernate" class EventWatcher : public QObject { Q_OBJECT private: qulonglong mReserveBrightness; qulonglong mDynamicBrightness; double m_reserveBrightnessPercent = 0.1; QLocalSocket *m_socket = nullptr; GlobalConfig *m_globalConfig = nullptr; QTimer *m_pInitTimer = nullptr; bool isSyncGlobal = true; static constexpr double DEFAULT_BRIGHTNESS_PERCENT = 70.0; int m_brightness350Nit; public: EventWatcher(); ~EventWatcher(); /** * @brief initEventWatcher * 初始化 */ void initEventWatcher(); void initAcpiSocket(); /** * @brief initBrightness * 初始化亮度 */ void initBrightness(); /** * @brief dealBrightnessMsg * 处理亮度信息 */ void dealBrightnessMsg(); /** * @brief initSettings * 获取用户设置亮度值 */ void getUserBrightness(); /** * @brief initConfig * 设置亮度值 */ void setBrightness(); void setGsettings(QString key, QVariant value); bool isNeedConfig(); /** * @brief controlPowerManagement * 控制电源管理dbus建立 */ int controlPowerManagement(const QString &type); void controlPowerManagement(const QString &type, const int &value); void controlPowerManagement(const QString &type, const bool &value); void controlPowerManagement(const QString &type, const QString &contrl); void controlPowerManagement(const QString &type, const qulonglong &brightness); void controlLogin1Manager(QString action); /** * @brief turnOffDisplay * 关闭显示器 */ void turnOffDisplay(); /** * @brief turnOnDisplay * 打开显示器 */ void turnOnDisplay(); /** * @brief suspend * 睡眠 */ void suspend(); /** * @brief hibernate * 休眠 */ void hibernate(); /** * @brief PowerOff * 关机 */ void powerOff(); void turnOffDisplaySignal(); void percentageLowRegulateBrightness(bool); bool checkDeviceModel(const QString &methodName); /* * =============================================== * 以下为成员变量,包括gsettings等设置相关变量 * =============================================== */ QGSettings *m_powerManagerGsettings; QGSettings *m_screenSaverGsettings; /** * @brief mMaxBrightness * 最大亮度值 */ qulonglong mMaxBrightness; /** * @brief mBrightness * 当前亮度值 */ qulonglong mBrightness; /** * @brief mUserBrightness * 用户配置的亮度值 */ qulonglong mUserBrightness; bool m_isFlemingX = false; FlemingX *m_flx = nullptr; /** * @brief m_isBrightnessEnhancement‌Supported * 是否支持亮度增强 */ bool m_isBrightnessEnhancementSupported = false; enum policy { Performance = 0, Balance, EnergySaving, Unknown, }; private: /** * @brief SyncFromGlobalConfig * 从全局电源配置同步到当前用户配置 */ void syncFromGlobalConfig(); /** * @brief SyncToGlobalConfig * 将当前用户配置同步到全局电源配置 */ void syncToGlobalConfig(); void setSuspend2HibernateTime(int seconds); public Q_SLOTS: void handleMiniBrightness(); private Q_SLOTS: void userActiveSlot(bool); void onInitTimerOut(); signals: }; #endif // EVENTWATCHER_H ukui-power-manager/PowerManagementDaemon/main.cpp0000664000175000017500000000373415167661430021104 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "powermanagementdamon.h" #include "ukui-power-test-tool/uptttestconfigpage.h" #include #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); QCoreApplication::setApplicationName(QObject::tr("ukui-powermanagement")); QCoreApplication::setApplicationVersion("0.1"); QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); QCommandLineOption runPowerTestToolOption("run-ptt", QCoreApplication::translate("main", "run power test tool")); parser.addOption(runPowerTestToolOption); parser.process(a); UpttTestConfigPage upttTestConfigPage; PowerManagementDamon powerManagementDamon; QTranslator translator; if (true == parser.isSet(runPowerTestToolOption)) { upttTestConfigPage.initUpttTestConfigPage(); upttTestConfigPage.show(); } else { initUkuiLog4qt("ukui-powermanagement"); if (translator.load(QLocale(), "ukui-power-manager-daemon", "_", QM_FILES_INSTALL_PATH)) { a.installTranslator(&translator); } else { qDebug() << "load ukui-power-manager-tray qm file error"; } powerManagementDamon.initPowerManagementDamon(); } return a.exec(); } ukui-power-manager/PowerManagementDaemon/globalconfig.h0000664000175000017500000000133415167661430022245 0ustar fengfeng#ifndef GLOBALCONFIG_H #define GLOBALCONFIG_H #include #include #include #include class GlobalConfig : public QObject { Q_OBJECT public: explicit GlobalConfig(QObject *parent = nullptr); ~GlobalConfig(); void initGlobalConfig(); bool writeGlobalParam(const QString & key, const QVariant &value); bool readGlobalParam(const QString & key, QVariant &data); bool readAllGlobalParam(QVariantMap &oMap); bool writeAllGlobalParam(QVariantMap &oMap); Q_SIGNALS: void userActiveSignal(bool); private Q_SLOTS: void userActiveSlot(bool); private: bool m_isInit = false; QDBusInterface *m_globalBus = nullptr; }; #endif // GLOBALCONFIG_H ukui-power-manager/PowerManagementDaemon/globalconfig.cpp0000664000175000017500000001111315167661430022574 0ustar fengfeng#include "globalconfig.h" #include #include #include #include #include #include #include #include #include #include #include "common.h" #define DBUS_GC_NAME "org.ukui.SettingsDaemon" #define DBUS_GC_SIGNAL_PATH "/GlobalSignal" #define DBUS_GC_SIGNAL "org.ukui.SettingsDaemon.GlobalSignal" #define DBUS_GC_INTERFACE_PATH "/globalconfig" #define DBUS_GC_INTERFACE "com.settings.daemon.interface" /*com.kylin.ukui.SettingsDaemon*/ #define SETTINGS_DAEMON_SYSTEMDBUS_NAME "com.kylin.ukui.SettingsDaemon" #define SETTINGS_DAEMON_SYSTEMDBUS_PATH "/globalconfig" #define SETTINGS_DAEMON_SYSTEMDBUS_INTERFACE "com.kylin.ukui.SettingsDaemon.interface" #define DBUS_POWER_MANAGER_SETTINGS "powerManager" #define DBUS_POWER_FULL_CONFIG "config" GlobalConfig::GlobalConfig(QObject *parent) : QObject(parent) { } GlobalConfig::~GlobalConfig() { if(m_isInit==true){ delete m_globalBus; m_globalBus = nullptr; m_isInit = false; } } void GlobalConfig::initGlobalConfig() { if(m_isInit==true){ return; } m_globalBus = new QDBusInterface(DBUS_GC_NAME, DBUS_GC_SIGNAL_PATH, DBUS_GC_SIGNAL, QDBusConnection::sessionBus()); QDBusInterface::connect(m_globalBus, SIGNAL(Active(bool)), this, SLOT(userActiveSlot(bool))); m_isInit = true; qDebug() << "connect success!!!!!!!!!!!!!!!!!!!!" << m_globalBus; } void GlobalConfig::userActiveSlot(bool isLogin) { qDebug() << "GlobalConfig user active " << isLogin; if(isLogin == 1){ Q_EMIT(userActiveSignal(true)); }else{ Q_EMIT(userActiveSignal(false)); } } bool GlobalConfig::writeGlobalParam(const QString & key, const QVariant &value) { QDBusInterface globalManager(SETTINGS_DAEMON_SYSTEMDBUS_NAME, \ SETTINGS_DAEMON_SYSTEMDBUS_PATH, \ SETTINGS_DAEMON_SYSTEMDBUS_INTERFACE, \ QDBusConnection::systemBus()); QList arguments; arguments< reply = globalManager.call("getGlobalConf", DBUS_POWER_MANAGER_SETTINGS, key); if (reply.error().type() == QDBusError::ErrorType::NoError) { data = reply.value(); return true; } else { qDebug() << "readPowerConf:"< reply = globalManager.call("getSchemaGlobalConf", DBUS_POWER_MANAGER_SETTINGS); if (reply.error().type() == QDBusError::ErrorType::NoError) { oMap= reply.value(); return oMap.contains(BRIGHTNESS_AC); } else { qDebug() << "readAllGlobalParam failed:"< arguments; arguments<. */ #include "powermanagementdamon.h" #include PowerManagementDamon::PowerManagementDamon() {} PowerManagementDamon::~PowerManagementDamon() { if (nullptr != idlenesswatcher) { delete idlenesswatcher; } if (nullptr != lidwatcher) { delete lidwatcher; } if (nullptr != eventwatcher) { delete eventwatcher; } if (nullptr != lowpowerwatcher) { delete lowpowerwatcher; } if (nullptr != gsettingwatcher) { delete gsettingwatcher; } } void PowerManagementDamon::initPowerManagementDamon() { UpmCustomDefaultGsettings upmCustomDefaultGsettings; upmCustomDefaultGsettings.setUpmCustomDefaultGsettings(); eventwatcher = new EventWatcher; eventwatcher->initEventWatcher(); if (false == CloudPlatform::self()->isCloudPlatform()) { idlenesswatcher = new IdlenessWatchcer; idlenesswatcher->initIdleWatcher(); } lidwatcher = new LidWatcher; lidwatcher->initLidWatcher(); lowpowerwatcher = new LowPowerWatcher; lowpowerwatcher->initLowPowerWatcher(); connect(lowpowerwatcher, &LowPowerWatcher::percentageLowSignal, eventwatcher, &EventWatcher::percentageLowRegulateBrightness); gsettingwatcher = new GsettingWatcher; gsettingwatcher->initGsettingWatcher(); m_externalInterface = new UpmExternalInterface(this); QDBusConnection connection = QDBusConnection::sessionBus(); if (!connection.registerService("org.ukui.powerManager")) { qWarning() << "QDbus register service failed reason:" << connection.lastError(); return; } if (!connection.registerObject("/PowerManager", m_externalInterface, QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals)) { qWarning() << "QDbus register object failed reason:" << connection.lastError(); } } ukui-power-manager/PowerManagementDaemon/cloudplatform.cpp0000664000175000017500000000263515167661430023032 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "cloudplatform.h" #include Q_GLOBAL_STATIC(CloudPlatform, s_cloudPlatform) CloudPlatform::CloudPlatform(QObject *parent) : QObject(parent) { QString cloudPlatForm = QString(QLatin1String(kdk_system_get_hostCloudPlatform())); QString hostType = QString(QLatin1String(kdk_system_get_hostVirtType())); qDebug() << "cloud platform name:" << cloudPlatForm << "host type:" << hostType; if ((cloudPlatForm == "huawei" || cloudPlatForm == "ctyun" || hostType != "none")) { m_isCloudPlatform = true; qDebug() << "is cloud platform"; } } CloudPlatform *CloudPlatform::self() { return s_cloudPlatform; } bool CloudPlatform::isCloudPlatform() { return m_isCloudPlatform; } ukui-power-manager/PowerManagementDaemon/upmexternalinterface.h0000664000175000017500000000346715167661430024055 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef UPMEXTERNALINTERFACE_H #define UPMEXTERNALINTERFACE_H #include #include #include #include #include "common.h" enum powersave_level { powersave_level_normal = 0, powersave_level_low, powersave_level_medium, powersave_level_high }; enum power_policy { power_policy_performance = 0, power_policy_balance, power_policy_powersave, power_policy_unknown }; class UpmExternalInterface : public QObject, protected QDBusContext { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.ukui.powerManager") public: explicit UpmExternalInterface(QObject *parent = nullptr); ~UpmExternalInterface(); private: int m_powersaveLevel; int m_currentPowerPolicy; bool m_batteryOnline; bool m_percentageLowState; QGSettings *m_powerGsettings; bool isOnBattery(); void updatePowersaveLevel(); private slots: void dealUPowerDBusMessage(QDBusMessage msg); void dealPercentageLowMessage(bool state); public slots: int getPowersaveLevel(); signals: void powersaveLevelChanged(int); }; #endif // UPMEXTERNALINTERFACE_H ukui-power-manager/PowerManagementDaemon/upmexternalinterface.cpp0000664000175000017500000000725415167661430024406 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "upmexternalinterface.h" UpmExternalInterface::UpmExternalInterface(QObject *parent) : QObject(parent) { m_powersaveLevel = powersave_level_normal; m_batteryOnline = isOnBattery(); m_powerGsettings = new QGSettings(POWER_MANAGER_SETTINGS, QByteArray(), this); m_currentPowerPolicy = m_powerGsettings->get(POWER_POLICY_CURRENT).toInt(); m_percentageLowState = false; updatePowersaveLevel(); QDBusConnection::systemBus().connect("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(dealUPowerDBusMessage(QDBusMessage))); QDBusConnection::sessionBus().connect("org.ukui.upower", "/upower/BatteryInfo", "org.ukui.upower.battery", "LowBatteryState", this, SLOT(dealPercentageLowMessage(bool))); connect(m_powerGsettings, &QGSettings::changed, this, [=](const QString &key) { if (key == POWER_POLICY_CURRENT) { m_currentPowerPolicy = m_powerGsettings->get(POWER_POLICY_CURRENT).toInt(); updatePowersaveLevel(); } }); } UpmExternalInterface::~UpmExternalInterface() {} bool UpmExternalInterface::isOnBattery() { QDBusInterface interface(UPOWER_SERVICE, UPOWER_PATH, FREEDESKTOP_UPOWER, QDBusConnection::systemBus()); QDBusReply reply = interface.call("Get", "org.freedesktop.UPower", "OnBattery"); if (reply.isValid()) { return reply.value().toBool(); } return false; } void UpmExternalInterface::dealUPowerDBusMessage(QDBusMessage msg) { const QDBusArgument &dbusArgs = msg.arguments().at(1).value(); QMap map; dbusArgs >> map; if (map.contains("OnBattery")) { m_batteryOnline = map.value(QString("OnBattery")).toBool(); updatePowersaveLevel(); } } void UpmExternalInterface::dealPercentageLowMessage(bool state) { if (state != m_percentageLowState) { m_percentageLowState = state; updatePowersaveLevel(); } } void UpmExternalInterface::updatePowersaveLevel() { int powersaveLevel = powersave_level_normal; if (true == m_batteryOnline) { if (true == m_percentageLowState) { powersaveLevel = powersave_level_medium; } else { if (power_policy_performance != m_currentPowerPolicy) { powersaveLevel = powersave_level_low; } } } if (powersaveLevel != m_powersaveLevel) { m_powersaveLevel = powersaveLevel; emit powersaveLevelChanged(m_powersaveLevel); } } int UpmExternalInterface::getPowersaveLevel() { return m_powersaveLevel; } ukui-power-manager/PowerManagementDaemon/eventwatcher.cpp0000664000175000017500000004712315167661430022657 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "eventwatcher.h" EventWatcher::EventWatcher() { const QByteArray powerManagerSettingsId(POWER_MANAGER_SETTINGS); m_powerManagerGsettings = new QGSettings(powerManagerSettingsId); const QByteArray screenSaverSettingsId(SCREEN_SAVER_SETTINGS); m_screenSaverGsettings = new QGSettings(screenSaverSettingsId); m_globalConfig = new GlobalConfig(); connect(m_globalConfig, SIGNAL(userActiveSignal(bool)), this, SLOT(userActiveSlot(bool))); m_pInitTimer = new QTimer(this); connect(m_pInitTimer, SIGNAL(timeout()), this, SLOT(onInitTimerOut())); m_isFlemingX = checkDeviceModel("isFlemingXModel"); m_reserveBrightnessPercent = m_isFlemingX ? 0.0 : 0.1; } EventWatcher::~EventWatcher() { delete m_powerManagerGsettings; delete m_screenSaverGsettings; delete m_globalConfig; delete m_pInitTimer; } void EventWatcher::initEventWatcher() { m_pInitTimer->start(1200); double userBrightnessPercent = 0.0f; initBrightness(); if (-1.0 == m_powerManagerGsettings->get(BRIGHTNESS_AC).toDouble()) { if (mDynamicBrightness > 0 && mUserBrightness > mReserveBrightness) { userBrightnessPercent = m_isFlemingX ? m_flx->convert2UiValue(mUserBrightness) : (mUserBrightness - mReserveBrightness) * 100 / mDynamicBrightness; } m_powerManagerGsettings->set(BRIGHTNESS_AC, userBrightnessPercent); qDebug() << "init user brightness ac is :" << userBrightnessPercent; getUserBrightness(); setBrightness(); } if (true == m_powerManagerGsettings->get(PERCENT_LOW_REDUCE_BRIGHTNESS).toBool()) { percentageLowRegulateBrightness(false); } connect(m_powerManagerGsettings, &QGSettings::changed, this, [=](const QString &key) { if (key == BRIGHTNESS_AC) { getUserBrightness(); setBrightness(); m_powerManagerGsettings->set(PERCENT_LOW_REDUCE_BRIGHTNESS, false); } }); initAcpiSocket(); } void EventWatcher::initAcpiSocket() { m_socket = new QLocalSocket(this); connect(m_socket, &QLocalSocket::connected, this, [=]() { qDebug() << "acpi socket connected success"; }); connect(m_socket, &QLocalSocket::readyRead, this, [=]() { QByteArray data = m_socket->readAll(); QString str = QString(data).simplified(); if (-1 != str.indexOf("thermal_zone LNXTHERM:00 000000f1 00000001", 0, Qt::CaseInsensitive)) { hibernate(); } }); m_socket->connectToServer("/var/run/acpid.socket"); qDebug() << m_socket->state(); } void EventWatcher::initBrightness() { QDBusInterface iface( POWER_MANAGEMENT_SERVICE, POWER_MANAGEMENT_PATH, POWER_MANAGEMENT_INTERFACE_NAME, QDBusConnection::systemBus()); QDBusReply reply = iface.call(IS_BRIGHTNESS_ENHANCEMENT_SUPPORTED); if (reply.isValid()) { m_isBrightnessEnhancementSupported = reply.value(); } else { qWarning() << "get " << IS_BRIGHTNESS_ENHANCEMENT_SUPPORTED << " fail"; } QString isSupportBrightnessEnhancement = m_isBrightnessEnhancementSupported ? "true" : "false"; qInfo() << "Is support brightness enhancement " << isSupportBrightnessEnhancement; mMaxBrightness = controlPowerManagement(GET_MAX_BRIGHTNESS); qDebug() << "max brightness is :" << mMaxBrightness; m_brightness350Nit = (int)(mMaxBrightness * BRIGHTNESS_ENHANCEMENT_THRESHOLD_PERCENT); mUserBrightness = controlPowerManagement(GET_BRIGHTNESS); qDebug() << "the current brightness value of the machine is :" << mUserBrightness; /** 未开启亮度增强,但是亮度值超过350nit对应的亮度,则设置为350nit对应的亮度 **/ if ((mUserBrightness > m_brightness350Nit) && m_isBrightnessEnhancementSupported && !m_powerManagerGsettings->get(BRIGHTNESS_ENHANCEMENT_SWITCH).toBool()) { qWarning() << "not enhancement but current brightness value over 350nit value:" << m_brightness350Nit; mUserBrightness = m_brightness350Nit; } // 如果支持亮度增强,百分百亮度对应350nit的亮度值;150%的亮度对应最大的亮度值;注意此时最小亮度值和动态变化亮度值已经是判断过亮度增强了 if (mMaxBrightness > 0 ) { mReserveBrightness = (m_isBrightnessEnhancementSupported ? m_brightness350Nit : mMaxBrightness) * m_reserveBrightnessPercent; mDynamicBrightness = (m_isBrightnessEnhancementSupported ? m_brightness350Nit : mMaxBrightness) - mReserveBrightness; qInfo() << "max brightness is " << mMaxBrightness << " reserve brightness is " << mReserveBrightness << " dynamicbbrightness is " << mDynamicBrightness; } else { qWarning() << "max brightness is invalued : " << mMaxBrightness; mReserveBrightness = 0; mDynamicBrightness = 0; } m_flx = new FlemingX(mMaxBrightness, this); qDebug() << "init reserve brightness is :" << mReserveBrightness; } void EventWatcher::getUserBrightness() { double userBrightnessPercent = m_powerManagerGsettings->get(BRIGHTNESS_AC).toDouble(); qDebug() << "user brightness percent is :" << userBrightnessPercent; if (userBrightnessPercent < 0) { qWarning() << "invalued user brightness percent " << userBrightnessPercent; return; } if (m_isBrightnessEnhancementSupported) {//支持亮度增强 if (m_powerManagerGsettings->get(BRIGHTNESS_ENHANCEMENT_SWITCH).toBool()) { //且开启了开关 userBrightnessPercent = qMin(userBrightnessPercent, 150.0); } else { userBrightnessPercent = qMin(userBrightnessPercent, 100.0); } if (userBrightnessPercent > 100.0) { mUserBrightness = m_brightness350Nit + (mMaxBrightness - m_brightness350Nit) * (userBrightnessPercent - 100.0)/50; } else { mUserBrightness = (userBrightnessPercent <= 20 ? (userBrightnessPercent * 0.5 + m_reserveBrightnessPercent * 100) : userBrightnessPercent)*m_brightness350Nit/100; } qInfo() << "support brightness enhancement user brightness percent " << userBrightnessPercent << " user brightness " << mUserBrightness; } else {//不支持亮度增强 userBrightnessPercent = qMin(userBrightnessPercent , 100.0);//最大值为20,则20%应该对应4,10%对应3,25%:对应5,80%对应16。 //最大值为200,则20%应该对应40,10%对应30,25%:50,80%对应160。 //最大值为255,则20%应该对应50.5,10%对应37.75,25%:63.75,80%对应20。 if(m_isFlemingX){ mUserBrightness = m_flx->convert2NodeValue(userBrightnessPercent); } else { mUserBrightness = (userBrightnessPercent <= 20 ? (userBrightnessPercent * 0.5 + m_reserveBrightnessPercent * 100) : userBrightnessPercent)*mMaxBrightness/100; } } qInfo() << "user brightness is :" << mUserBrightness; } void EventWatcher::setBrightness() { controlPowerManagement(REGULATE_BRIGHTNESS, mUserBrightness); } void EventWatcher::setGsettings(QString key, QVariant value) { m_powerManagerGsettings->set(key, value); } void EventWatcher::turnOffDisplay() { //调用关闭显示器的接口 if ("wayland" == qgetenv("XDG_SESSION_TYPE")) { system("export QT_QPA_PLATFORM=wayland && kscreen-doctor --dpms off &"); } else { system("xset dpms force off &"); } qDebug() << "The display is turned off" << qgetenv("XDG_SESSION_TYPE"); } void EventWatcher::turnOnDisplay() { if ("wayland" == qgetenv("XDG_SESSION_TYPE")) { system("export QT_QPA_PLATFORM=wayland && kscreen-doctor --dpms on &"); } else { system("xset dpms force on &"); } qDebug() << "The display is turned on" << qgetenv("XDG_SESSION_TYPE"); } void EventWatcher::suspend() { controlLogin1Manager(LOGIN1_DBUS_SET_SUSPEND); } void EventWatcher::hibernate() { controlLogin1Manager(LOGIN1_DBUS_SET_HIBERNATE); } void EventWatcher::powerOff() { controlLogin1Manager(LOGIN1_DBUS_SET_POWEROFF); } void EventWatcher::turnOffDisplaySignal() { const bool state = true; QDBusMessage msg = QDBusMessage::createSignal("/", "ukui.power.manager", "TurnOffDisplay"); msg << state; QDBusConnection::sessionBus().send(msg); qDebug() << "send turn off display msg"; } void EventWatcher::percentageLowRegulateBrightness(bool percentageLowState) { if (true == m_isFlemingX) { qDebug() << "flemingx机器,不支持低电量下降低亮度"; return; } m_powerManagerGsettings->blockSignals(true); double userBrightnessPercent = m_powerManagerGsettings->get(BRIGHTNESS_AC).toDouble(); if (true == percentageLowState) { userBrightnessPercent = userBrightnessPercent > 10 ? userBrightnessPercent - 10 : 0; } else { if (true == m_powerManagerGsettings->get(PERCENT_LOW_REDUCE_BRIGHTNESS).toBool()) { userBrightnessPercent += 10; } else { m_powerManagerGsettings->blockSignals(false); return ; } } userBrightnessPercent = qMin(userBrightnessPercent, m_isBrightnessEnhancementSupported ? 150.0 : 100.0); if (userBrightnessPercent <= 100) {//即使支持亮度增强模式,百分比小于100时直接计算即可,因为mReserveBrightness、mDynamicBrightness均计算过亮度增强因素 mUserBrightness = (userBrightnessPercent <= 20 ? (userBrightnessPercent * 0.5 + m_reserveBrightnessPercent * 100) : userBrightnessPercent) * (mReserveBrightness + mDynamicBrightness) / 100; } else { if (m_powerManagerGsettings->get(BRIGHTNESS_ENHANCEMENT_SWITCH).toBool()) { // 百分比大于100且开启了增强模式开关 mUserBrightness = m_brightness350Nit + (mMaxBrightness - m_brightness350Nit) * (userBrightnessPercent - 100.0)/50; } else { mUserBrightness = m_brightness350Nit; } } controlPowerManagement(REGULATE_BRIGHTNESS, mUserBrightness); m_powerManagerGsettings->set(BRIGHTNESS_AC, userBrightnessPercent); m_powerManagerGsettings->set(PERCENT_LOW_REDUCE_BRIGHTNESS, percentageLowState); QTimer::singleShot(10, this, [=]() { m_powerManagerGsettings->blockSignals(false); }); } void EventWatcher::handleMiniBrightness() { setBrightness(); } void EventWatcher::controlLogin1Manager(QString action) { QDBusInterface dbusInterface("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", QDBusConnection::systemBus()); dbusInterface.call(action, false); qInfo() << "system will" << action; } bool EventWatcher::checkDeviceModel(const QString &methodName) { QDBusInterface iface( POWER_MANAGEMENT_SERVICE, POWER_MANAGEMENT_PATH, POWER_MANAGEMENT_INTERFACE_NAME, QDBusConnection::systemBus()); // 检查接口是否有效 if (!iface.isValid()) { QString errorMsg = QDBusConnection::systemBus().lastError().message(); qWarning() << "设备检测错误 - DBus接口无效:" << errorMsg; return false; } // 调用DBus方法 QDBusReply reply = iface.call(methodName); // 检查回复是否有效 if (!reply.isValid()) { qWarning() << "设备检测失败 - DBus调用错误:" << reply.error().name() << "-" << reply.error().message(); return false; } return reply.value(); } //此处代码后期可以进行优化 int EventWatcher::controlPowerManagement(const QString &type) { QDBusInterface iface( POWER_MANAGEMENT_SERVICE, POWER_MANAGEMENT_PATH, POWER_MANAGEMENT_INTERFACE_NAME, QDBusConnection::systemBus()); QDBusReply reply = iface.call(type); return reply.value(); } void EventWatcher::controlPowerManagement(const QString &type, const qulonglong &brightness) { QDBusInterface iface( POWER_MANAGEMENT_SERVICE, POWER_MANAGEMENT_PATH, POWER_MANAGEMENT_INTERFACE_NAME, QDBusConnection::systemBus()); iface.call(type, brightness); } void EventWatcher::controlPowerManagement(const QString &type, const int &value) { QDBusInterface iface( POWER_MANAGEMENT_SERVICE, POWER_MANAGEMENT_PATH, POWER_MANAGEMENT_INTERFACE_NAME, QDBusConnection::systemBus()); iface.call(type, value); } void EventWatcher::controlPowerManagement(const QString &type, const bool &value) { QDBusInterface iface( POWER_MANAGEMENT_SERVICE, POWER_MANAGEMENT_PATH, POWER_MANAGEMENT_INTERFACE_NAME, QDBusConnection::systemBus()); iface.call(type, value); } void EventWatcher::controlPowerManagement(const QString &type, const QString &contrl) { QDBusInterface iface( POWER_MANAGEMENT_SERVICE, POWER_MANAGEMENT_PATH, POWER_MANAGEMENT_INTERFACE_NAME, QDBusConnection::systemBus()); iface.call(type, contrl); } void EventWatcher::userActiveSlot(bool isLogin) { if(isLogin == true) { syncFromGlobalConfig(); qDebug() <<"user login syncFromGlobalConfig"; } else { syncToGlobalConfig(); qDebug() <<"user logout SyncToGlobalConfig"; } } void EventWatcher::onInitTimerOut() { static int retry = 0; double userBrightnessPercent = 0.0f; initBrightness(); if (0 == mMaxBrightness && retry++ < 3) { qDebug() << "mMaxBrightness get error!"; return; } m_pInitTimer->stop(); qDebug() << "mMaxBrightness:"<< mMaxBrightness << retry; m_globalConfig->initGlobalConfig(); syncFromGlobalConfig(); qDebug() << "init EventWatcher"; if (m_powerManagerGsettings->keys().contains(HIBERNATE_COMPUTER_AC_KEY)) { int hibernateTimeSeconds = m_powerManagerGsettings->get(HIBERNATE_COMPUTER_AC_KEY).toInt(); setSuspend2HibernateTime(hibernateTimeSeconds); qDebug() << "Set initial Suspend2HibernateTime to" << hibernateTimeSeconds << "seconds"; } if (-1.0 == m_powerManagerGsettings->get(BRIGHTNESS_AC).toDouble()) { if (mDynamicBrightness > 0 && mUserBrightness > mReserveBrightness) { if ((100 * mUserBrightness / (mReserveBrightness + mDynamicBrightness)) > 20) { userBrightnessPercent = 100 * mUserBrightness / (mReserveBrightness + mDynamicBrightness); } else { userBrightnessPercent = 2 * 100 * mUserBrightness / (mReserveBrightness + mDynamicBrightness) - m_reserveBrightnessPercent * 100; } } else { qWarning() << "currnt brightness " << mUserBrightness << "is below ReserveBrightness " << mReserveBrightness << " or Dynamic Brightness invalued " << mDynamicBrightness; userBrightnessPercent = 0.0; } if (mUserBrightness == 0.0) { userBrightnessPercent = DEFAULT_BRIGHTNESS_PERCENT; //默认亮度为70% qWarning() << "user brightness is 0, set default brightness percent:" << userBrightnessPercent; } m_powerManagerGsettings->set(BRIGHTNESS_AC, userBrightnessPercent); qDebug() << "init user brightness ac is :" << userBrightnessPercent; getUserBrightness(); setBrightness(); m_globalConfig->writeGlobalParam(BRIGHTNESS_AC, m_powerManagerGsettings->get(BRIGHTNESS_AC)); } if (true == m_powerManagerGsettings->get(PERCENT_LOW_REDUCE_BRIGHTNESS).toBool()) { percentageLowRegulateBrightness(false); } connect(m_powerManagerGsettings, &QGSettings::changed, this, [=](const QString &key) { if (key == BRIGHTNESS_AC) { getUserBrightness(); setBrightness(); m_powerManagerGsettings->set(PERCENT_LOW_REDUCE_BRIGHTNESS, false); } if (key == BRIGHTNESS_ENHANCEMENT_SWITCH) { qInfo() << "brightness enhancement switch is " << (m_powerManagerGsettings->get(BRIGHTNESS_ENHANCEMENT_SWITCH).toBool() ? "open" : "close"); if (!m_powerManagerGsettings->get(BRIGHTNESS_ENHANCEMENT_SWITCH).toBool() && (m_powerManagerGsettings->get(BRIGHTNESS_AC).toInt() > 100)) { qWarning() << "now brightness over 100% reset 100%"; m_powerManagerGsettings->set(BRIGHTNESS_AC, 100);//由connect信号处理亮度百分比变化 } if (key == HIBERNATE_COMPUTER_AC_KEY) { int hibernateTimeSeconds = m_powerManagerGsettings->get(HIBERNATE_COMPUTER_AC_KEY).toInt(); setSuspend2HibernateTime(hibernateTimeSeconds); qDebug() << "Set Suspend2HibernateTime to" << hibernateTimeSeconds << "seconds"; } } m_globalConfig->writeGlobalParam(key, m_powerManagerGsettings->get(key)); }); connect(m_screenSaverGsettings, &QGSettings::changed, this, [=](const QString &key) { qDebug() << "write screen saver settings"; if (key == SLEEPACTIVATIONENABLED || key == CLOSEACTIVATIONENABLED) { m_globalConfig->writeGlobalParam(key, m_screenSaverGsettings->get(key)); qDebug() << "write screen saver settings"; } }); initAcpiSocket(); } void EventWatcher::syncFromGlobalConfig() { QVariantMap map; bool ret = m_globalConfig->readAllGlobalParam(map); if(ret == true){ Q_FOREACH(const QString key, map.keys()) { qDebug()<<"syncFromGlobalConfig set:"<set(key,map[key]); } else{ m_powerManagerGsettings->set(key,map[key]); } } } } void EventWatcher::syncToGlobalConfig() { QVariantMap map; Q_FOREACH(const QString key, m_powerManagerGsettings->keys()) { qDebug()<<"syncFromGlobalConfig set:"<get(key); m_powerManagerGsettings->set(key, m_powerManagerGsettings->get(key)); } m_globalConfig->writeAllGlobalParam(map); } void EventWatcher::setSuspend2HibernateTime(int seconds) { QDBusInterface dbusInterface("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", QDBusConnection::systemBus()); if (!dbusInterface.isValid()) { qWarning() << "Failed to create DBus interface for login1 Manager:" << QDBusConnection::systemBus().lastError().message(); return; } // -1 表示从不,其他值为秒数,需转换为分钟 int minutes = seconds == -1 ? seconds : seconds / 60; QDBusReply reply = dbusInterface.call("Suspend2HibernateTime", minutes); if (!reply.isValid()) { qWarning() << "Failed to set Suspend2HibernateTime:" << reply.error().message(); } else { qInfo() << "Successfully set Suspend2HibernateTime to" << minutes << "minutes (" << seconds << "seconds)"; } } ukui-power-manager/PowerManagementDaemon/lidwatcher/0000775000175000017500000000000015167661430021573 5ustar fengfengukui-power-manager/PowerManagementDaemon/lidwatcher/lidwatcher.cpp0000664000175000017500000001373415167661430024435 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "lidwatcher.h" LidWatcher::LidWatcher() {} LidWatcher::~LidWatcher() {} void LidWatcher::initLidWatcher() { inhibitSystemdLogin(); QDBusConnection::systemBus().connect("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "PrepareForSleep", this, SLOT(dealWakeUpSignal(bool))); QDBusConnection::systemBus().connect( UPOWER_SERVICE, UPOWER_PATH, FREEDESKTOP_UPOWER, "PropertiesChanged", this, SLOT(dealLidWatcherMssage(QDBusMessage))); m_displayState = true; m_lidState = false; } void LidWatcher::inhibitSystemdLogin() { QDBusInterface manager( QStringLiteral("org.freedesktop.login1"), QStringLiteral("/org/freedesktop/login1"), QStringLiteral("org.freedesktop.login1.Manager"), QDBusConnection::systemBus()); QDBusReply reply = manager.call( QStringLiteral("Inhibit"), QStringLiteral("handle-lid-switch"), QStringLiteral("powermanagment"), QStringLiteral("ukui-powermanagement blocked LidSwitch!"), QStringLiteral("block")); if (reply.isValid()) { m_logindLock = reply.value(); qDebug() << "Inhibit got:" << m_logindLock.fileDescriptor(); } else { qDebug() << "Error from inhibit:" << reply.error(); } } void LidWatcher::dealLidWatcherMssage(QDBusMessage msg) { const QDBusArgument &dbusArgs = msg.arguments().at(1).value(); QMap map; dbusArgs >> map; if (map.contains("LidIsClosed")) { m_lidState = map.value(QString("LidIsClosed")).toBool(); QString contrl; if (getBatteryState()) { contrl = m_powerManagerGsettings->get(BUTTON_LID_BATTERY).toString(); qDebug() << "lid close contrl on battery state:" << contrl; } else { contrl = m_powerManagerGsettings->get(BUTTON_LID_AC).toString(); qDebug() << "lid close contrl on ac state:" << contrl; } if (true == m_lidState) { if ("blank" == contrl) { QProcess process; //执行命令 process.start("ukui-screensaver-command -b lid"); //等待命令执行结束 process.waitForFinished(); turnOffDisplay(); turnOffDisplaySignal(); m_displayState = false; } else if ("suspend" == contrl) { suspend(); } else if ("shutdown" == contrl) { powerOff(); } else if ("hibernate" == contrl) { hibernate(); } } else { if ("blank" == contrl && false == m_displayState) { turnOnDisplay(); m_displayState = true; } } } } void LidWatcher::resetLidAction(void) { QString contrl; QDBusInterface iface(UPOWER_SERVICE, UPOWER_PATH, FREEDESKTOP_UPOWER, QDBusConnection::systemBus()); QDBusReply reply = iface.call("Get", "org.freedesktop.UPower", "LidIsClosed"); if (reply.isValid()) { m_lidState = reply.value().toBool(); qDebug() << "lid state:" << m_lidState; if (getBatteryState()) { contrl = m_powerManagerGsettings->get(BUTTON_LID_BATTERY).toString(); } else { contrl = m_powerManagerGsettings->get(BUTTON_LID_AC).toString(); } qDebug() << "lid close contrl:" << contrl; if (m_lidState) { if ("blank" == contrl) { QProcess process; //执行命令 process.start("ukui-screensaver-command -b lid"); //等待命令执行结束 process.waitForFinished(); turnOffDisplay(); turnOffDisplaySignal(); m_displayState = false; } else if ("suspend" == contrl) { suspend(); } else if ("shutdown" == contrl) { powerOff(); } else if ("hibernate" == contrl) { hibernate(); } } else { if ("blank" == contrl && false == m_displayState) { turnOnDisplay(); m_displayState = true; } } } else { qDebug() << "Failed to get lid closed event!"; } } bool LidWatcher::getBatteryState() { QDBusInterface iface(UPOWER_SERVICE, UPOWER_PATH, FREEDESKTOP_UPOWER, QDBusConnection::systemBus()); QDBusReply reply = iface.call("Get", "org.freedesktop.UPower", "OnBattery"); if (reply.isValid()) { return reply.value().toBool(); } qDebug() << "The battery status obtained by closing the cover is abnormal!"; return false; } void LidWatcher::dealWakeUpSignal(bool isSleepState) { //在合盖后,通过其他唤醒源将机器唤醒时,保证合盖操作 if (isSleepState) { qDebug() << "The computer is going to sleep "; } else { if (m_lidState) { qWarning() << "Sleep is awakened unexpectedly!"; resetLidAction(); } else { qDebug() << "The computer wakes up "; } } } ukui-power-manager/PowerManagementDaemon/lidwatcher/lidwatcher.h0000664000175000017500000000237215167661430024076 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef LIDWATCHER_H #define LIDWATCHER_H #include "eventwatcher.h" class LidWatcher : public EventWatcher { Q_OBJECT public: LidWatcher(); ~LidWatcher(); /** * @brief initLidWatcher * 初始化监听盒盖 */ void initLidWatcher(); private: void inhibitSystemdLogin(); bool getBatteryState(); QDBusUnixFileDescriptor m_logindLock; void resetLidAction(); bool m_displayState; bool m_lidState; private slots: void dealLidWatcherMssage(QDBusMessage); void dealWakeUpSignal(bool); }; #endif // LIDWATCHER_H ukui-power-manager/PowerManagementDaemon/lowpowerwatcher/0000775000175000017500000000000015167661430022701 5ustar fengfengukui-power-manager/PowerManagementDaemon/lowpowerwatcher/lowpowerwatcher.h0000664000175000017500000000624315167661430026313 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef LOWPOWERWATCHER_H #define LOWPOWERWATCHER_H #include #include "acwatcher/acwatcher.h" #include "eventwatcher.h" class LowPowerWatcher : public EventWatcher { Q_OBJECT public: LowPowerWatcher(); ~LowPowerWatcher(); /** * @brief initLowPowerWatcher * 初始化LowPowerWatcher */ void initLowPowerWatcher(); bool lowPowerState(); private: /** * @brief initConnect * 初始化连接 */ void initConnect(); /** * @brief readSettings * 读取gsetting设置 */ void readSettings(); /** * @brief readPercentage * 从UPower读取当前电量百分比 * @return */ double readPercentage(); /** * @brief lowBatteryNotify * 低电量消息通知 */ void lowBatteryNotify(); /** * @brief veryLowBatteryNotify * @param msg * 极低电量执行操作通知 */ void veryLowBatteryNotify(const QString &msg); /** * @brief veryLowBatteryContrl * 极低电量进行操作 */ void veryLowBatteryContrl(const QString &contrl); /** * @brief veryLowBatteryContrlStop * 极低电量操作计时器打断 */ void veryLowBatteryContrlStop(); quint32 notifySend(const QString &type, const QString &arg, QString soundName); /** * @brief mPercentageLow * 当前电量百分比 */ double mPercentageLow; /** * @brief mSetPercentageLow * 用户设置的低电量百分比 */ int mSetPercentageLow; /** * @brief mPercentageAction * 用户设置的极低电量百分比 */ int mPercentageAction; /** * @brief mActionCriticalBattery * 极低电量进行的操作设置 */ QString mActionCriticalBattery; // AcWatcher *mAcWatcher; QTimer *mContrlTimer; bool mLowPowerState; bool mNotifyState; quint32 m_notificationId = 0; quint32 m_criticalBatteryNotificationId = 0; // signals: // /** // * @brief lowPowerChanged // * 进入低电量状态信号 // */ // void lowPowerChanged(bool); //降低亮度 void reduceBrightness(); //增加亮度 void increaseBrightness(); void closeNotify(quint32 notificationId); private slots: void dealPowerStateMssage(bool state); void dealLowBatteryMssage(bool state); void dealVeryLowBatteryMssage(bool state); signals: void percentageLowSignal(bool); }; #endif // LOWPOWERWATCHER_H ukui-power-manager/PowerManagementDaemon/lowpowerwatcher/lowpowerwatcher.cpp0000664000175000017500000001732515167661430026651 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "lowpowerwatcher.h" LowPowerWatcher::LowPowerWatcher() {} LowPowerWatcher::~LowPowerWatcher() { delete mContrlTimer; } void LowPowerWatcher::initLowPowerWatcher() { mContrlTimer = new QTimer; initConnect(); mPercentageLow = readPercentage(); if (mSetPercentageLow >= mPercentageLow) { mLowPowerState = true; } else { mLowPowerState = false; } mNotifyState = false; } void LowPowerWatcher::initConnect() { readSettings(); connect(m_powerManagerGsettings, &QGSettings::changed, this, [=](const QString &key) { readSettings(); if (key == PERCENTAGE_ACTION || key == ACTION_CRITICAL_BATTERY) { veryLowBatteryContrlStop(); } }); QDBusConnection::sessionBus().connect( UKUI_UPOWER_SERVICE, UKUI_UPOWER_PATH, UKUI_UPOWER_INTERFACE, "PowerState", this, SLOT(dealPowerStateMssage(bool))); QDBusConnection::sessionBus().connect( UKUI_UPOWER_SERVICE, UKUI_UPOWER_BATTERY_PATH, UKUI_UPOWER_BATTERY_INTERFACE, "LowBatteryState", this, SLOT(dealLowBatteryMssage(bool))); QDBusConnection::sessionBus().connect( UKUI_UPOWER_SERVICE, UKUI_UPOWER_BATTERY_PATH, UKUI_UPOWER_BATTERY_INTERFACE, "VeryLowBatteryState", this, SLOT(dealVeryLowBatteryMssage(bool))); connect(mContrlTimer, &QTimer::timeout, [this] { veryLowBatteryContrl(mActionCriticalBattery); mContrlTimer->stop(); }); } void LowPowerWatcher::readSettings() { mSetPercentageLow = m_powerManagerGsettings->get(PERCENTAGE_LOW).toInt(); qDebug() << "mSetPercentageLow:" << mSetPercentageLow; mPercentageAction = m_powerManagerGsettings->get(PERCENTAGE_ACTION).toInt(); qDebug() << "mPercentageAction:" << mPercentageAction; mActionCriticalBattery = m_powerManagerGsettings->get(ACTION_CRITICAL_BATTERY).toString(); qDebug() << "mActionCriticalBattery:" << mActionCriticalBattery; } double LowPowerWatcher::readPercentage() { double value; QDBusInterface iface(UPOWER_SERVICE, UPOWER_DISPLAY_PATH, FREEDESKTOP_UPOWER, QDBusConnection::systemBus()); QDBusReply reply = iface.call("Get", "org.freedesktop.UPower.Device", "Percentage"); if (reply.isValid()) { value = reply.value().toDouble(); } else { qDebug() << "Power percentage get error!"; } return value; } void LowPowerWatcher::dealLowBatteryMssage(bool state) { mLowPowerState = state; qWarning()<<"LowPowerWatcher::dealLowBatteryMssage state is :"<< state; if (mLowPowerState) { lowBatteryNotify(); } emit percentageLowSignal(mLowPowerState); } void LowPowerWatcher::dealVeryLowBatteryMssage(bool state) { qInfo() << "critical battery state:" << state; if (true == state) { if (false == mNotifyState) { veryLowBatteryNotify(mActionCriticalBattery); } } else { if (m_criticalBatteryNotificationId != 0) { closeNotify(m_criticalBatteryNotificationId); m_criticalBatteryNotificationId = 0; } veryLowBatteryContrlStop(); } } void LowPowerWatcher::dealPowerStateMssage(bool state) { if (!state) { if (m_notificationId != 0) { closeNotify(m_notificationId); m_notificationId = 0; } } } bool LowPowerWatcher::lowPowerState() { return mLowPowerState; } void LowPowerWatcher::lowBatteryNotify() { mPercentageLow = readPercentage(); if (mPercentageLow > mPercentageAction) { QString mType = tr("Low battery notification"); m_notificationId = notifySend(mType, tr("The system enters a low battery state"),"battery-low"); qInfo() << "low battery notification id:" << m_notificationId; } } void LowPowerWatcher::veryLowBatteryNotify(const QString &msg) { mPercentageLow = readPercentage(); QString mType = tr("Very low battery notification"); QString sound = "battery-low"; if (m_criticalBatteryNotificationId == 0) { if ("blank" == msg) { m_criticalBatteryNotificationId = notifySend(mType, QString(tr("Current power is:%1%. The system will turn off the display in one minute")).arg(mPercentageLow),sound); } else if ("suspend" == msg) { m_criticalBatteryNotificationId = notifySend(mType, QString(tr("Current power is:%1%,The system will suspend in one minute")).arg(mPercentageLow),sound); } else if ("shutdown" == msg) { m_criticalBatteryNotificationId = notifySend(mType, QString(tr("Current power is:%1%,The system will shutdown in one minute")).arg(mPercentageLow),sound); } else if ("hibernate" == msg) { m_criticalBatteryNotificationId = notifySend(mType, QString(tr("Current power is:%1%,The system will hibernate in one minute")).arg(mPercentageLow),sound); } qInfo() << "new critical battery notification id:" << m_criticalBatteryNotificationId; } else { qInfo() << "old critical battery notification id:" << m_criticalBatteryNotificationId; } mNotifyState = true; mContrlTimer->start(60000); } void LowPowerWatcher::veryLowBatteryContrl(const QString &contrl) { if ("blank" == contrl) { QProcess process; //执行命令 process.start("ukui-screensaver-command -b lid"); //等待命令执行结束 process.waitForFinished(); turnOffDisplay(); } else if ("suspend" == contrl) { suspend(); } else if ("shutdown" == contrl) { powerOff(); } else if ("hibernate" == contrl) { hibernate(); } mNotifyState = false; } void LowPowerWatcher::veryLowBatteryContrlStop() { if (mContrlTimer->isActive()) { mContrlTimer->stop(); mNotifyState = false; } } quint32 LowPowerWatcher::notifySend(const QString &type, const QString &arg, QString soundName) { QDBusInterface iface( "org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", QDBusConnection::sessionBus()); QList args; QStringList argg; QMap pear_map; pear_map.insert("sound-name", soundName); pear_map.insert("x-ukui-popup-timeout", -1); args << tr("Power Manager") << ((unsigned int)0) << QString("ukui-power-manager") << type //显示的是什么类型的信息//系统升级 << arg //显示的具体信息 << argg << pear_map << (int)0; QDBusReply reply = iface.callWithArgumentList(QDBus::AutoDetect, "Notify", args); if (reply.isValid()) { return reply.value(); } return 0; } void LowPowerWatcher::closeNotify(quint32 notificationId) { QDBusInterface iface( "org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", QDBusConnection::sessionBus()); iface.call("CloseNotification", notificationId); qInfo() << "close notify id:" << notificationId; } ukui-power-manager/PowerManagementDaemon/hardware/0000775000175000017500000000000015167661430021242 5ustar fengfengukui-power-manager/PowerManagementDaemon/hardware/huawei/0000775000175000017500000000000015167661430022524 5ustar fengfengukui-power-manager/PowerManagementDaemon/hardware/huawei/flemingx.h0000664000175000017500000000336015167661430024510 0ustar fengfeng/* * Copyright 2025 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef FLEMINGX_H #define FLEMINGX_H #include class FlemingX : public QObject { Q_OBJECT public: explicit FlemingX(int maxbrightness, QObject *parent = nullptr); FlemingX() = delete; int convert2NodeValue(int UiValue) const; int convert2UiValue(int nodeValue) const; private: inline int reverseCalculateUsingFormulaSmall50(const int currentValue) const; inline int reverseCalculateUsingFormulaBeyond50(const int currentValue) const; inline int calculateUsingFormulaSmall50(const int currentValue) const; inline int calculateUsingFormulaBeyond50(const int currentValue) const; void initFormulaParam(int maxBrightness); void test(); private: int m_maxBrightness = 0; qreal m_a = 1.94; //[0-50] double m_b = 0.017755579807; //[50-100] const qreal m_k = 4.0; static constexpr double ROUNDING_FACTOR = 0.5; static constexpr double POWER_EXPONENT = 2.2; static constexpr double MAX_UI = 100; const int m_commonThreshold = 50; int m_defaultValueThreshold = 101; }; #endif // FLEMINGX_H ukui-power-manager/PowerManagementDaemon/hardware/huawei/flemingx.cpp0000664000175000017500000000600415167661430025041 0ustar fengfeng/* * Copyright 2025 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "flemingx.h" #include #include #include /* - flemingX的OLED调光策略 - 设置值 = b * UI值^2.2+k;(50~100) - 设置值 = a * UI值 + k;(0~50) - (UI值,设置值)带入计算。 - (0,4)带入公式1计算出K,带入50,得出设置1。 - (100,450),把设置1带入公式2,50带入UI值,k带入得出a。 - 然后50%时UI值时两边的值一样。 - 需要对公式逆向出默认值。 */ FlemingX::FlemingX(int maxbrightness, QObject *parent): QObject(parent) { initFormulaParam(maxbrightness); } int FlemingX::convert2NodeValue(int UiValue) const { return UiValue > m_commonThreshold ? calculateUsingFormulaBeyond50(UiValue) : calculateUsingFormulaSmall50(UiValue); } int FlemingX::convert2UiValue(int nodeValue) const { return nodeValue > m_defaultValueThreshold ? reverseCalculateUsingFormulaBeyond50(nodeValue):reverseCalculateUsingFormulaSmall50(nodeValue); } void FlemingX::initFormulaParam(int maxBrightness) { m_b = (maxBrightness - m_k)/(std::pow(MAX_UI, POWER_EXPONENT)); m_defaultValueThreshold = m_b * std::pow(m_commonThreshold, POWER_EXPONENT) + m_k; m_a = (m_defaultValueThreshold - m_k) / m_commonThreshold; qDebug()<< __func__ << m_a << m_b << m_k << m_defaultValueThreshold; } void FlemingX::test() { for(int circle = 0; circle <= 100; circle++) { int value = convert2NodeValue(circle); int defautValue = convert2UiValue(value); qDebug()<<__func__<<__LINE__<(std::pow(temp, 1.0 / POWER_EXPONENT) + ROUNDING_FACTOR); } inline int FlemingX::calculateUsingFormulaSmall50(int currentValue) const { int ret = m_a * currentValue * 1.0 + m_k + ROUNDING_FACTOR; return ret; } inline int FlemingX::calculateUsingFormulaBeyond50(int currentValue) const { qreal ret = m_b * std::pow(currentValue* 1.0, POWER_EXPONENT) + m_k + ROUNDING_FACTOR; return ret; } ukui-power-manager/PowerManagementDaemon/powermanagementdamon.h0000664000175000017500000000310715167661430024027 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef POWERMANAGEMENTDAMON_H #define POWERMANAGEMENTDAMON_H #include #include #include "idle/idlenesswatcher.h" #include "lidwatcher/lidwatcher.h" #include "acwatcher/acwatcher.h" #include "eventwatcher.h" #include "gsettingwatcher/gsettingwatcher.h" #include "lowpowerwatcher/lowpowerwatcher.h" #include "upmcustomdefaultgsettings.h" #include "cloudplatform.h" #include "upmexternalinterface.h" class PowerManagementDamon : public QObject { Q_OBJECT public: PowerManagementDamon(); ~PowerManagementDamon(); void initPowerManagementDamon(); private: IdlenessWatchcer *idlenesswatcher = nullptr; LidWatcher *lidwatcher = nullptr; EventWatcher *eventwatcher = nullptr; GsettingWatcher *gsettingwatcher = nullptr; LowPowerWatcher *lowpowerwatcher = nullptr; UpmExternalInterface *m_externalInterface = nullptr; }; #endif // POWERMANAGEMENTDAMON_H ukui-power-manager/PowerManagementDaemon/powermanagercenter.h0000664000175000017500000000023415167661430023505 0ustar fengfeng#ifndef POWERMANAGERCENTER_H #define POWERMANAGERCENTER_H class powermanagercenter { public: powermanagercenter(); }; #endif // POWERMANAGERCENTER_H ukui-power-manager/PowerManagementDaemon/PowerManagementDaemon/0000775000175000017500000000000015167661415023665 5ustar fengfengukui-power-manager/PowerManagementDaemon/PowerManagementDaemon/.gitignore0000664000175000017500000000134515167661415025660 0ustar fengfeng# This file is used to ignore files which are generated # ---------------------------------------------------------------------------- *~ *.autosave *.a *.core *.moc *.o *.obj *.orig *.rej *.so *.so.* *_pch.h.cpp *_resource.rc *.qm .#* *.*# core !core/ tags .DS_Store .directory *.debug Makefile* *.prl *.app moc_*.cpp ui_*.h qrc_*.cpp Thumbs.db *.res *.rc /.qmake.cache /.qmake.stash # qtcreator generated files *.pro.user* # xemacs temporary files *.flc # Vim temporary files .*.swp # Visual Studio generated files *.ib_pdb_index *.idb *.ilk *.pdb *.sln *.suo *.vcproj *vcproj.*.*.user *.ncb *.sdf *.opensdf *.vcxproj *vcxproj.* # MinGW generated files *.Debug *.Release # Python byte code *.pyc # Binaries # -------- *.dll *.exe ukui-power-manager/PowerManagementDaemon/upmcustomdefaultgsettings.cpp0000664000175000017500000001724015167661430025506 0ustar fengfeng/* * Copyright 2024 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upmcustomdefaultgsettings.h" #include #include #include #include "common.h" enum policy { Performance = 0, Balance, EnergySaving, }; UpmCustomDefaultGsettings::UpmCustomDefaultGsettings(QObject *parent) : QObject(parent) { m_upmGsettings = new QGSettings(QByteArray(POWER_MANAGER_SETTINGS), QByteArray(), this); if (true == m_upmGsettings->get(PRE_POWER_MODE).toBool()) { return; } getHardwareInfo(); m_globalConfig = new QSettings(UPM_GLOBAL_GSETTINGS_CONFIG_FILE, QSettings::IniFormat, this); QString extendConfigFilePath; if (true == getExtendConfigFile(extendConfigFilePath)) { m_extendConfig = new QSettings(extendConfigFilePath, QSettings::IniFormat, this); m_extendConfig->beginGroup("product"); QStringList productList = m_extendConfig->allKeys(); Q_FOREACH (const QString &product, productList) { if (m_hardwareInfo.contains(product, Qt::CaseInsensitive)) { if (1 == m_extendConfig->value(product).toInt()) { m_productGroup = product; } break; } } m_extendConfig->endGroup(); } } UpmCustomDefaultGsettings::~UpmCustomDefaultGsettings() {} void UpmCustomDefaultGsettings::setUpmCustomDefaultGsettings() { if (true == m_upmGsettings->get(PRE_POWER_MODE).toBool()) { return; } setCustomDefaultCpuPolicyAc(); setCustomDefaultCpuPolicyBattery(); setCustomDefaultIdleBrightness(); setCustomDefaultIdlePowerPolicyAuto(); setCustomDefaultSleepComputerAc(); setCustomDefaultSleepComputerBattery(); m_upmGsettings->set(PRE_POWER_MODE, true); } void UpmCustomDefaultGsettings::getHardwareInfo() { if (false == readAll(UPM_HARDWARE_INFO_FILE, m_hardwareInfo)) { qDebug() << "get hardware info failed"; } } void UpmCustomDefaultGsettings::setCustomDefaultCpuPolicyAc() { if (true == getGlobalCpuDefaultPolicy(UPM_GROUP_DEFAULT_POLICY_AC, UPM_KEY_BALANCE_MODE_BOARD_NAME)) { m_upmGsettings->set(POWER_POLICY_AC, Balance); return ; } if (true == getGlobalCpuDefaultPolicy(UPM_GROUP_DEFAULT_POLICY_AC, UPM_KEY_POWERSAVE_MODE_BOARD_NAME)) { m_upmGsettings->set(POWER_POLICY_AC, EnergySaving); return ; } if (nullptr != m_extendConfig) { QVariant value; if (true == readConfig(m_extendConfig, UPM_GROUP_EXTEND_BRAND_GENERIC_CONFIG, POWER_POLICY_AC, value)) { m_upmGsettings->set(POWER_POLICY_AC, value.toInt()); } if (true == readConfig(m_extendConfig, m_productGroup, POWER_POLICY_AC, value)) { m_upmGsettings->set(POWER_POLICY_AC, value.toInt()); } } } void UpmCustomDefaultGsettings::setCustomDefaultCpuPolicyBattery() { if (true == getGlobalCpuDefaultPolicy(UPM_GROUP_DEFAULT_POLICY_BATTERY, UPM_KEY_BALANCE_MODE_BOARD_NAME)) { m_upmGsettings->set(POWER_POLICY_BATTERY, Balance); return ; } if (true == getGlobalCpuDefaultPolicy(UPM_GROUP_DEFAULT_POLICY_BATTERY, UPM_KEY_POWERSAVE_MODE_BOARD_NAME)) { m_upmGsettings->set(POWER_POLICY_BATTERY, EnergySaving); return ; } if (nullptr != m_extendConfig) { QVariant value; if (true == readConfig(m_extendConfig, UPM_GROUP_EXTEND_BRAND_GENERIC_CONFIG, POWER_POLICY_BATTERY, value)) { m_upmGsettings->set(POWER_POLICY_BATTERY, value.toInt()); } if (true == readConfig(m_extendConfig, m_productGroup, POWER_POLICY_BATTERY, value)) { m_upmGsettings->set(POWER_POLICY_BATTERY, value.toInt()); } } } void UpmCustomDefaultGsettings::setCustomDefaultIdleBrightness() { if (nullptr != m_extendConfig) { QVariant value; if (true == readConfig(m_extendConfig, m_productGroup, IDLE_BRIGHTNESS, value)) { m_upmGsettings->set(IDLE_BRIGHTNESS, value.toInt()); } } } void UpmCustomDefaultGsettings::setCustomDefaultIdlePowerPolicyAuto() { if (nullptr != m_extendConfig) { QVariant value; if (true == readConfig(m_extendConfig, m_productGroup, IDLE_POWER_POLICY_AUTO, value)) { if (1 == value.toInt()) { m_upmGsettings->set(IDLE_POWER_POLICY_AUTO, true); } } } } void UpmCustomDefaultGsettings::setCustomDefaultSleepComputerAc() { if (nullptr != m_extendConfig) { QVariant value; if (true == readConfig(m_extendConfig, m_productGroup, SLEEP_COMPUTER_AC, value)) { m_upmGsettings->set(SLEEP_COMPUTER_AC, value.toInt()); } } } void UpmCustomDefaultGsettings::setCustomDefaultSleepComputerBattery() { if (nullptr != m_extendConfig) { QVariant value; if (true == readConfig(m_extendConfig, m_productGroup, SLEEP_COMPUTER_BATTERY, value)) { m_upmGsettings->set(SLEEP_COMPUTER_BATTERY, value.toInt()); } } } bool UpmCustomDefaultGsettings::getGlobalCpuDefaultPolicy(const QString &group, const QString &key) { QVariant value; if (true == readConfig(m_globalConfig, group, key, value)) { QStringList boards = value.toString().split(","); Q_FOREACH (const QString &board, boards) { if (m_hardwareInfo.contains(board, Qt::CaseInsensitive) && !board.isEmpty()) { return true; } } } return false; } bool UpmCustomDefaultGsettings::readConfig( QSettings *settings, const QString &group, const QString &key, QVariant &value) { if (nullptr == settings) { return false; } settings->beginGroup(group); value = settings->value(key, UPM_NO_THIS_KEY); settings->endGroup(); if (UPM_NO_THIS_KEY == value.toString()) { return false; } return true; } bool UpmCustomDefaultGsettings::getExtendConfigFile(QString &configFilePath) { QDir extendConfigDir(UPM_EXTEND_GSETTINGS_CONFIG_PATH); if (true == extendConfigDir.exists()) { QStringList extendConfigs = extendConfigDir.entryList(QDir::Files | QDir::NoDotAndDotDot); Q_FOREACH (const QString &extendConfig, extendConfigs) { QStringList fileName = extendConfig.split("."); if (m_hardwareInfo.contains(fileName[0], Qt::CaseInsensitive)) { configFilePath = QString(UPM_EXTEND_GSETTINGS_CONFIG_PATH) + extendConfig; return true; } } } return false; } bool UpmCustomDefaultGsettings::readAll(const QString &filePath, QString &content) { QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "read file error :" << filePath; return false; } content = file.readAll(); file.close(); return true; } ukui-power-manager/PowerManagementDaemon/error.h0000664000175000017500000000006315167661430020746 0ustar fengfeng#ifndef ERROR_H #define ERROR_H #endif // ERROR_H ukui-power-manager/PowerManagementDaemon/upmcustomdefaultgsettings.h0000664000175000017500000000525115167661430025152 0ustar fengfeng/* * Copyright 2024 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPMCUSTOMDEFAULTGSETTINGS_H #define UPMCUSTOMDEFAULTGSETTINGS_H #include #include #include #define UPM_NO_THIS_KEY QStringLiteral("no-this-key") #define UPM_HARDWARE_INFO_FILE QStringLiteral("/sys/class/dmi/id/modalias") #define UPM_GLOBAL_GSETTINGS_CONFIG_FILE QStringLiteral("/usr/share/ukui/ukui-power-manager/upm-gsettings-global.conf") #define UPM_EXTEND_GSETTINGS_CONFIG_PATH QStringLiteral("/usr/share/ukui/ukui-power-manager/upm-gsettings-extend.d/") #define UPM_GROUP_DEFAULT_POLICY_AC QStringLiteral("default-policy-ac") #define UPM_GROUP_DEFAULT_POLICY_BATTERY QStringLiteral("default-policy-battery") #define UPM_KEY_BALANCE_MODE_BOARD_NAME QStringLiteral("balanceModeBoardName") #define UPM_KEY_POWERSAVE_MODE_BOARD_NAME QStringLiteral("powersaveModeBoardName") #define UPM_GROUP_EXTEND_BRAND_GENERIC_CONFIG QStringLiteral("Brand-generic-config") class UpmCustomDefaultGsettings : public QObject { Q_OBJECT public: explicit UpmCustomDefaultGsettings(QObject *parent = nullptr); ~UpmCustomDefaultGsettings(); void setUpmCustomDefaultGsettings(); private: QString m_hardwareInfo = ""; QSettings *m_globalConfig = nullptr; QSettings *m_extendConfig = nullptr; QString m_productGroup = ""; QGSettings *m_upmGsettings = nullptr; void getHardwareInfo(); void setCustomDefaultCpuPolicyAc(); void setCustomDefaultCpuPolicyBattery(); void setCustomDefaultIdleBrightness(); void setCustomDefaultIdlePowerPolicyAuto(); void setCustomDefaultSleepComputerAc(); void setCustomDefaultSleepComputerBattery(); bool getGlobalCpuDefaultPolicy(const QString &group, const QString &key); bool readConfig(QSettings *settings, const QString &group, const QString &key, QVariant &value); bool getExtendConfigFile(QString &configFilePath); bool readAll(const QString &filePath, QString &content); signals: }; #endif // UPMCUSTOMDEFAULTGSETTINGS_H ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/0000775000175000017500000000000015167661430023504 5ustar fengfengukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upttbrightnessconfig.cpp0000664000175000017500000000321515167661430030464 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "upttbrightnessconfig.h" UpttBrightnessConfig::UpttBrightnessConfig(QWidget *parent) : QWidget(parent) { QHBoxLayout *mainLayout = new QHBoxLayout(this); m_sliderLabel = new QLabel("屏幕亮度", this); m_sliderLabel->setFixedWidth(100); m_slider = new QSlider(Qt::Horizontal, this); m_slider->setMinimum(0); m_slider->setMaximum(100); m_slider->setFixedWidth(300); m_slider->setValue(80); m_valueLable = new QLabel(this); m_valueLable->setText(QString::number(m_slider->value())); m_valueLable->setContentsMargins(30, 0, 0, 0); mainLayout->addWidget(m_sliderLabel); mainLayout->addWidget(m_slider); mainLayout->addWidget(m_valueLable); connect(m_slider, &QSlider::valueChanged, [&](int value) { m_valueLable->setText(QString::number(value)); }); } UpttBrightnessConfig::~UpttBrightnessConfig() {} int UpttBrightnessConfig::getBrightnessPercentage() { return m_slider->value(); } ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upttbrightnessconfig.h0000664000175000017500000000224115167661430030127 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef UPTTBRIGHTNESSCONFIG_H #define UPTTBRIGHTNESSCONFIG_H #include #include #include #include #include class UpttBrightnessConfig : public QWidget { Q_OBJECT public: explicit UpttBrightnessConfig(QWidget *parent = nullptr); ~UpttBrightnessConfig(); int getBrightnessPercentage(); private: QLabel *m_sliderLabel; QLabel *m_valueLable; QSlider *m_slider; }; #endif // UPTTBRIGHTNESSCONFIG_H ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/uptttestconfigpage.cpp0000664000175000017500000005570215167661430030140 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "uptttestconfigpage.h" #include #include #include UpttTestConfigPage::UpttTestConfigPage(QWidget *parent) : QWidget(parent) { m_energyFull = UpmUpowerDBus::self()->getEnergyFull(); m_energyFullDesign = UpmUpowerDBus::self()->getEnergyFullDesign(); m_batteryHealth = m_energyFull / m_energyFullDesign; qDebug() << "battery health:" << m_batteryHealth; } UpttTestConfigPage::~UpttTestConfigPage() { if (!m_batteryDateVector.isEmpty()) { clearBatteryDate(); } if (nullptr != m_energyRateTestTimer) { delete m_energyRateTestTimer; } } void UpttTestConfigPage::initUpttTestConfigPage() { initTestConfigPageUI(); connect(m_runTestButton, &UpttRunTestButton::runEnduranceTestSignal, this, &UpttTestConfigPage::runEnduranceTest); connect(m_runTestButton, &UpttRunTestButton::runEnergyRateTestSignal, this, &UpttTestConfigPage::runEnergyRateTest); connect(m_runTestButton, &UpttRunTestButton::stopTestSignal, this, &UpttTestConfigPage::stopTest); connect(m_runTestButton, &UpttRunTestButton::acOnlineTestNotRunSignal, this, &UpttTestConfigPage::acOnlineTestNotRun); connect(UpmUpowerDBus::self(), &UpmUpowerDBus::batteryInfoChanged, this, &UpttTestConfigPage::recordBatteryDate); } void UpttTestConfigPage::initTestConfigPageUI() { setWindowIcon(QIcon("ukui-power-manager")); setFixedSize(800, 600); setWindowTitle("续航测试简陋版"); QVBoxLayout *mainLayout = new QVBoxLayout(this); m_upttCpuPolicyConfig = new UpttCpuPolicyConfig(this); m_upttBrightnessConfig = new UpttBrightnessConfig(this); m_balanceModeReduceFrequency = new QCheckBox("平衡模式降低CPU频率"); m_balanceModeReduceFrequency->setChecked(false); m_autoSwitchCpuCore = new QCheckBox("自动开关CPU核心"); m_autoSwitchCpuCore->setChecked(false); m_idleReserveCpu0 = new QCheckBox("系统空闲时仅保留cpu0"); m_idleReserveCpu0->setChecked(false); m_idleReduceBrightness = new QCheckBox("系统空闲时降低屏幕亮度"); m_idleReduceBrightness->setChecked(true); m_idleTurnoffDisplay = new QCheckBox("系统空闲时不关闭显示器"); m_idleTurnoffDisplay->setChecked(true); m_idleSystemSuspend = new QCheckBox("系统空闲时不进入睡眠"); m_idleSystemSuspend->setChecked(true); m_disableScreenSaver = new QCheckBox("系统空闲时不开启屏幕保护"); m_disableScreenSaver->setChecked(true); m_idlePowerPolicyAuto = new QCheckBox("系统空闲时切换节能模式"); m_idlePowerPolicyAuto->setChecked(false); m_criticalPercentageDoNothing = new QCheckBox("低电量无操作"); m_criticalPercentageDoNothing->setChecked(true); m_runTestButton = new UpttRunTestButton(this); m_hintMessage = new QLabel(this); mainLayout->addWidget(m_upttCpuPolicyConfig); mainLayout->addWidget(m_upttBrightnessConfig); mainLayout->addWidget(m_balanceModeReduceFrequency); mainLayout->addWidget(m_autoSwitchCpuCore); mainLayout->addWidget(m_idleReserveCpu0); mainLayout->addWidget(m_idleReduceBrightness); mainLayout->addWidget(m_idleTurnoffDisplay); mainLayout->addWidget(m_idleSystemSuspend); mainLayout->addWidget(m_disableScreenSaver); mainLayout->addWidget(m_idlePowerPolicyAuto); mainLayout->addWidget(m_criticalPercentageDoNothing); mainLayout->addWidget(m_runTestButton); mainLayout->addWidget(m_hintMessage); mainLayout->addStretch(); } void UpttTestConfigPage::setTestConfig() { UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_AUTO_BRIGHTENSS, false); int cpuPolicy = m_upttCpuPolicyConfig->getPowerPolicyBattery(); QDBusInterface dBusInterface(UPM_DBUS_SERVICE, UPM_DBUS_PATH, UPM_DBUS_INTERFACE, QDBusConnection::systemBus()); dBusInterface.call("EnableReduceCpuFrequency", m_balanceModeReduceFrequency->isChecked()); dBusInterface.call("EnableAutoSwitchCpuCore", m_autoSwitchCpuCore->isChecked(), cpuPolicy); dBusInterface.call("EnableSystemIdleReserveCpu0", m_idleReserveCpu0->isChecked(), cpuPolicy); if (true == m_idleReduceBrightness->isChecked()) { UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_IDLE_BRIGHTNESS, 70); } else { UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_IDLE_BRIGHTNESS, 100); } if (true == m_idleTurnoffDisplay->isChecked()) { UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_SLEEP_DISPLAY_BATTERY, -1); } else { UpmGsettings::self()->resetGsettingsConfig(GSETTINGS_KEY_SLEEP_DISPLAY_BATTERY); } if (true == m_idleSystemSuspend->isChecked()) { UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_SLEEP_COMPUTER_BATTERY, -1); } else { UpmGsettings::self()->resetGsettingsConfig(GSETTINGS_KEY_SLEEP_COMPUTER_BATTERY); } if (true == m_disableScreenSaver->isChecked()) { UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_IDLE_DELAY, -1); } else { UpmGsettings::self()->resetGsettingsConfig(GSETTINGS_KEY_IDLE_DELAY); } if (true == m_idlePowerPolicyAuto->isChecked()) { UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_IDLE_POWER_POLICY_AUTO, true); } else { UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_IDLE_POWER_POLICY_AUTO, false); } if (true == m_criticalPercentageDoNothing->isChecked()) { UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_ACTION_CRITICAL_BATTERY, "nothing"); m_minBatteryPercentage = 2; } else { UpmGsettings::self()->resetGsettingsConfig(GSETTINGS_KEY_ACTION_CRITICAL_BATTERY); QVariant value; if (true == UpmGsettings::self()->getGsettingsConfig(GSETTINGS_KEY_PERCENTAGE_ACTION, value)) { m_minBatteryPercentage = value.toInt(); } } UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_POWER_POLICY_BATTERY, cpuPolicy); UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_BRIGHTNESS_AC, m_upttBrightnessConfig->getBrightnessPercentage()); QDBusReply reply = dBusInterface.call("GetBrightness"); m_startBrightness = reply.value(); } void UpttTestConfigPage::runEnduranceTest() { clearBatteryDate(); setTestConfig(); m_hasNewReport = false; m_runTestDateTime = QDateTime::currentDateTime(); m_energyNow = UpmUpowerDBus::self()->getEnergyNow(); m_testIsRunning = true; m_testType = endurance_test; showMinimized(); } void UpttTestConfigPage::runEnergyRateTest() { clearBatteryDate(); if (nullptr == m_energyRateTestTimer) { m_energyRateTestTimer = new QTimer(); connect(m_energyRateTestTimer, &QTimer::timeout, this, &UpttTestConfigPage::dealEnergyRateTestTimer); } setTestConfig(); m_testType = energy_rate_test; m_hasNewReport = false; m_testIsRunning = true; m_refreshBatteryInfo = true; UpmUpowerDBus::self()->refreshBatteryInfo(); m_energyRateTestTimer->start(360000); showMinimized(); } void UpttTestConfigPage::stopTest() { if (true == m_hasNewReport) { m_hintMessage->setText("测试结束,有新的测试报告"); } else { m_hintMessage->setText("测试结束"); } activateWindow(); } void UpttTestConfigPage::acOnlineTestNotRun() { m_hintMessage->setText("电源未拔出,1分钟内拔出电源,将开始测试,否则结束测试"); } void UpttTestConfigPage::recordBatteryDate(int index, QStringList batteryInfo) { if (false == m_testIsRunning) { return ; } int percentage = UpmUpowerDBus::self()->getBatteryPercentage(); if (endurance_test == m_testType) { if (percentage < 6) { if (percentage != m_batteryDateVector.last()->getBatteryPercentage()) { UpttBatteryDate *batteryDate = new UpttBatteryDate(percentage, UpmUpowerDBus::self()->getEnergyNow(), m_batteryDateVector.last()->getRecordDateTime(), m_batteryDateVector.last()->getBatteryEnergy()); m_batteryDateVector << batteryDate; } if (percentage <= m_minBatteryPercentage) { m_testIsRunning = false; createEnduranceTestReport(); } } else { if (0 == percentage % 10 && 100 != percentage) { if (0 == m_batteryDateVector.size()) { UpttBatteryDate *batteryDate = new UpttBatteryDate(percentage, UpmUpowerDBus::self()->getEnergyNow(), m_runTestDateTime, m_energyNow); m_batteryDateVector << batteryDate; if (true == m_idleReduceBrightness->isChecked()) { QDBusInterface dBusInterface(UPM_DBUS_SERVICE, UPM_DBUS_PATH, UPM_DBUS_INTERFACE, QDBusConnection::systemBus()); QDBusReply reply = dBusInterface.call("GetBrightness"); m_stopBrightness = reply.value(); } } else { if (percentage != m_batteryDateVector.last()->getBatteryPercentage()) { UpttBatteryDate *batteryDate = new UpttBatteryDate(percentage, UpmUpowerDBus::self()->getEnergyNow(), m_batteryDateVector.last()->getRecordDateTime(), m_batteryDateVector.last()->getBatteryEnergy()); m_batteryDateVector << batteryDate; } } } } } else if (energy_rate_test == m_testType) { if (true == m_refreshBatteryInfo) { if (0 == m_batteryDateVector.size()) { UpttBatteryDate *batteryDate = new UpttBatteryDate( percentage, UpmUpowerDBus::self()->getEnergyNow(), QDateTime::currentDateTime(), 0); m_batteryDateVector << batteryDate; } else { UpttBatteryDate *batteryDate = new UpttBatteryDate(percentage, UpmUpowerDBus::self()->getEnergyNow(), m_batteryDateVector.last()->getRecordDateTime(), m_batteryDateVector.last()->getBatteryEnergy()); m_batteryDateVector << batteryDate; createEnergyRateTestReport(); m_energyRateTestTimer->stop(); } m_refreshBatteryInfo = false; } } else { ; } } void UpttTestConfigPage::dealEnergyRateTestTimer() { m_refreshBatteryInfo = true; UpmUpowerDBus::self()->refreshBatteryInfo(); } void UpttTestConfigPage::createReportPath() { if (endurance_test == m_testType) { m_testReportDir = QDir::homePath() + QString("/power-test/endurance_test/"); } else if (energy_rate_test == m_testType) { m_testReportDir = QDir::homePath() + QString("/power-test/energy_rate_test/"); } else { return ; } QDir testReportDir(m_testReportDir); if (false == testReportDir.exists()) { testReportDir.mkpath(m_testReportDir); } } void UpttTestConfigPage::createEnduranceTestReport() { createReportPath(); QString reportFileName = m_testReportDir + QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") + QString(".report"); QFile reportFile(reportFileName); if (!reportFile.open(QIODevice::WriteOnly | QIODevice::Text)) { return ; } QString reportLine("---------------<测试配置>----------------\n"); reportFile.write(reportLine.toUtf8()); QDBusInterface dBusInterface(UPM_DBUS_SERVICE, UPM_DBUS_PATH, UPM_DBUS_INTERFACE, QDBusConnection::systemBus()); QDBusReply replyCpuCoreNum = dBusInterface.call("GetCpuCoreNum"); for (int i = 0; i < replyCpuCoreNum.value(); ++i) { QDBusReply replyPolicy = dBusInterface.call("GetCpuCorePolicy", i); reportLine = QString("\n").arg(i).arg(replyPolicy.value().simplified()); reportFile.write(reportLine.toUtf8()); } QStringList policyList = {"performance", "balance", "powersave"}; reportLine = QString("<工作模式: %1>\n").arg(policyList[m_upttCpuPolicyConfig->getPowerPolicyBattery()]); reportFile.write(reportLine.toUtf8()); reportLine = QString("<屏幕亮度百分比: %1%>\n").arg(m_upttBrightnessConfig->getBrightnessPercentage()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<平衡模式降低CPU频率: %1>\n").arg(m_balanceModeReduceFrequency->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<自动开关CPU核心: %1>\n").arg(m_autoSwitchCpuCore->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<系统空闲时仅保留cpu0: %1>\n").arg(m_idleReserveCpu0->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<系统空闲时降低屏幕亮度: %1>\n").arg(m_idleReduceBrightness->isChecked()); reportFile.write(reportLine.toUtf8()); if (true == m_idleReduceBrightness->isChecked()) { reportLine = QString("<开始亮度: %1>\n").arg(m_startBrightness); reportFile.write(reportLine.toUtf8()); reportLine = QString("<结束亮度: %1>\n").arg(m_stopBrightness); reportFile.write(reportLine.toUtf8()); } reportLine = QString("<系统空闲时不关闭显示器: %1>\n").arg(m_idleTurnoffDisplay->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<系统空闲时不进入睡眠: %1>\n").arg(m_idleSystemSuspend->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<系统空闲时不开启屏幕保护: %1>\n").arg(m_disableScreenSaver->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<系统空闲时切换节能模式: %1>\n").arg(m_idlePowerPolicyAuto->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<低电量无操作: %1>\n").arg(m_criticalPercentageDoNothing->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("\n---------------<电池信息>---------------\n"); reportFile.write(reportLine.toUtf8()); reportLine = QString("<开始时间: %1>\n").arg(m_runTestDateTime.toString("hh:mm:ss")); reportFile.write(reportLine.toUtf8()); reportLine = QString("<当前电量: %1wh>\n").arg(m_energyNow); reportFile.write(reportLine.toUtf8()); reportLine = QString("<满电电量: %1wh>\n").arg(m_energyFull); reportFile.write(reportLine.toUtf8()); reportLine = QString("<设计电量: %1wh>\n").arg(m_energyFullDesign); reportFile.write(reportLine.toUtf8()); reportLine = QString("<电池健康: %1>\n").arg(m_batteryHealth); reportFile.write(reportLine.toUtf8()); reportLine = QString("\n---------------<测试数据>---------------\n"); reportFile.write(reportLine.toUtf8()); int secondsOfEndurance = 0; for (int i = 0; i < m_batteryDateVector.size(); ++i) { reportLine = QString("<当前时间: %1> <百分比: %2%> <间隔时间: %3s> <当前电量: %4wh> <功率: w>\n") .arg(m_batteryDateVector[i]->getRecordDateTime().toString("hh:mm:ss")) .arg(m_batteryDateVector[i]->getBatteryPercentage()) .arg(m_batteryDateVector[i]->getElapsedTime()) .arg(m_batteryDateVector[i]->getBatteryEnergy()) .arg(m_batteryDateVector[i]->getBatteryEnergyRate()); reportFile.write(reportLine.toUtf8()); secondsOfEndurance += m_batteryDateVector[i]->getElapsedTime(); } reportLine = QString("<续航时间: %1 : %2s>\n") .arg(secondsToTimeFormat(secondsOfEndurance)) .arg(secondsOfEndurance); reportFile.write(reportLine.toUtf8()); reportFile.close(); m_hasNewReport = true; m_runTestButton->stopTest(); QDBusInterface dbusInterface("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", QDBusConnection::systemBus()); dbusInterface.call("PowerOff", true); } void UpttTestConfigPage::createEnergyRateTestReport() { createReportPath(); QString reportFileName = m_testReportDir + QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") + QString(".report"); QFile reportFile(reportFileName); if (!reportFile.open(QIODevice::WriteOnly | QIODevice::Text)) { return ; } QString reportLine("---------------<测试配置>----------------\n"); reportFile.write(reportLine.toUtf8()); QDBusInterface dBusInterface(UPM_DBUS_SERVICE, UPM_DBUS_PATH, UPM_DBUS_INTERFACE, QDBusConnection::systemBus()); QDBusReply replyCpuCoreNum = dBusInterface.call("GetCpuCoreNum"); for (int i = 0; i < replyCpuCoreNum.value(); ++i) { QDBusReply replyPolicy = dBusInterface.call("GetCpuCorePolicy", i); reportLine = QString("\n").arg(i).arg(replyPolicy.value().simplified()); reportFile.write(reportLine.toUtf8()); } QStringList policyList = {"performance", "balance", "powersave"}; reportLine = QString("<工作模式: %1>\n").arg(policyList[m_upttCpuPolicyConfig->getPowerPolicyBattery()]); reportFile.write(reportLine.toUtf8()); reportLine = QString("<屏幕亮度百分比: %1%>\n").arg(m_upttBrightnessConfig->getBrightnessPercentage()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<平衡模式降低CPU频率: %1>\n").arg(m_balanceModeReduceFrequency->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<自动开关CPU核心: %1>\n").arg(m_autoSwitchCpuCore->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<系统空闲时仅保留cpu0: %1>\n").arg(m_idleReserveCpu0->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<系统空闲时降低屏幕亮度: %1>\n").arg(m_idleReduceBrightness->isChecked()); reportFile.write(reportLine.toUtf8()); if (true == m_idleReduceBrightness->isChecked()) { QDBusInterface dBusInterface(UPM_DBUS_SERVICE, UPM_DBUS_PATH, UPM_DBUS_INTERFACE, QDBusConnection::systemBus()); QDBusReply reply = dBusInterface.call("GetBrightness"); m_stopBrightness = reply.value(); reportLine = QString("<开始亮度: %1>\n").arg(m_startBrightness); reportFile.write(reportLine.toUtf8()); reportLine = QString("<结束亮度: %1>\n").arg(m_stopBrightness); reportFile.write(reportLine.toUtf8()); } reportLine = QString("<系统空闲时不关闭显示器: %1>\n").arg(m_idleTurnoffDisplay->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<系统空闲时不进入睡眠: %1>\n").arg(m_idleSystemSuspend->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<系统空闲时不开启屏幕保护: %1>\n").arg(m_disableScreenSaver->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<系统空闲时切换节能模式: %1>\n").arg(m_idlePowerPolicyAuto->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<低电量无操作: %1>\n").arg(m_criticalPercentageDoNothing->isChecked()); reportFile.write(reportLine.toUtf8()); reportLine = QString("\n---------------<测试数据>---------------\n"); reportFile.write(reportLine.toUtf8()); reportLine = QString("<开始时间: %1> <开始时电池百分比: %2%> <开始时电池电量: %3wh>\n") .arg(m_batteryDateVector[0]->getRecordDateTime().toString("hh:mm:ss")) .arg(m_batteryDateVector[0]->getBatteryPercentage()) .arg(m_batteryDateVector[0]->getBatteryEnergy()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<结束时间: %1> <结束时电池百分比: %2%> <结束时电池电量: %3wh>\n") .arg(m_batteryDateVector[1]->getRecordDateTime().toString("hh:mm:ss")) .arg(m_batteryDateVector[1]->getBatteryPercentage()) .arg(m_batteryDateVector[1]->getBatteryEnergy()); reportFile.write(reportLine.toUtf8()); reportLine = QString("<放电功率: %1w>\n").arg(m_batteryDateVector[1]->getBatteryEnergyRate()); reportFile.write(reportLine.toUtf8()); reportFile.close(); m_hasNewReport = true; m_runTestButton->stopTest(); } void UpttTestConfigPage::clearBatteryDate() { for (int i = 0; i < m_batteryDateVector.size(); ++i) { delete m_batteryDateVector.at(i); } m_batteryDateVector.clear(); } QString UpttTestConfigPage::secondsToTimeFormat(int seconds) { int hours = seconds / 3600; // 计算小时数 int remainingSeconds = seconds % 3600; // 计算剩余秒数 int minutes = remainingSeconds / 60; // 从剩余秒数中计算分钟数 int secondsInMinutes = remainingSeconds % 60; // 剩余的秒数(不包括用于计算分钟的秒数) // 格式化输出,例如 "HH:MM:SS" 的格式 return QString("%1:%2:%3").arg(hours).arg(minutes).arg(secondsInMinutes); } ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upttcpupolicyconfig.h0000664000175000017500000000237415167661430027775 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef UPTTCPUPOLICYCONFIG_H #define UPTTCPUPOLICYCONFIG_H #include #include #include #include #include class UpttCpuPolicyConfig : public QWidget { Q_OBJECT public: explicit UpttCpuPolicyConfig(QWidget *parent = nullptr); ~UpttCpuPolicyConfig(); int getPowerPolicyBattery(); private: QLabel *m_policyLabel; QButtonGroup *m_policyGroup; QRadioButton *m_powersaveRadio; QRadioButton *m_balanceRadio; QRadioButton *m_performanceRadio; }; #endif // UPTTCPUPOLICYCONFIG_H ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upttruntestbutton.h0000664000175000017500000000340015167661430027527 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef UPTTRUNTESTBUTTON_H #define UPTTRUNTESTBUTTON_H #include #include #include #include #include "upower-dbus/upm_upowerdbus.h" class UpttRunTestButton : public QWidget { Q_OBJECT public: explicit UpttRunTestButton(QWidget *parent = nullptr); ~UpttRunTestButton(); void stopTest(); private: QPushButton *m_runEnduranceTestButton; QPushButton *m_runEnergyRateTestButton; QPushButton *m_stopTestButton; QTimer *m_acOnlineHintTimer; enum test_state { stop_test, run_endurance_test, run_energy_rate_test }; int m_testState = stop_test; void initRunTestButtonUI(); void initAcOnlineHintTimer(); private slots: void dealRunEnduranceTestButtonClicked(); void dealRunEnergyRateTestButtonClicked(); void dealStopTestButtonClicked(); void dealAcOnlineStateChanged(); signals: void runEnduranceTestSignal(); void runEnergyRateTestSignal(); void stopTestSignal(); void acOnlineTestNotRunSignal(); }; #endif // UPTTRUNTESTBUTTON_H ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upower-dbus/0000775000175000017500000000000015167661430025760 5ustar fengfengukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upower-dbus/upowerlinepowerdbus.cpp0000664000175000017500000000466115167661430032617 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upowerlinepowerdbus.h" UpowerLinePowerDBus::UpowerLinePowerDBus(int linePowerId, const QString &linePowerDBusPath, QObject *parent) : QObject(parent), m_linePowerId(linePowerId) { m_DBusInterface = new QDBusInterface("org.freedesktop.UPower", linePowerDBusPath, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus(), this); QDBusConnection::systemBus().connect("org.freedesktop.UPower", linePowerDBusPath, "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(dealLinePowerPropertiesMessage(QDBusMessage))); QDBusReply reply = m_DBusInterface->call("Get", "org.freedesktop.UPower.Device", "Online"); if (reply.isValid()) { m_acOnlineState = reply.value().toBool(); } else { m_acOnlineState = false; } } UpowerLinePowerDBus::~UpowerLinePowerDBus() {} void UpowerLinePowerDBus::dealLinePowerPropertiesMessage(QDBusMessage msg) { const QDBusArgument &dbusArgs = msg.arguments().at(1).value(); QMap map; dbusArgs >> map; if (map.contains("Online")) { bool acOnlineState = map.value(QString("Online")).toBool(); if (m_acOnlineState != acOnlineState) { m_acOnlineState = acOnlineState; emit acOnlineStateChanged(m_linePowerId, m_acOnlineState); } } } int UpowerLinePowerDBus::getAcOnlineState() { return m_acOnlineState; } ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upower-dbus/upowerbatterydbus.h0000664000175000017500000000355315167661430031731 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPOWERBATTERYDBUS_H #define UPOWERBATTERYDBUS_H #include #include #include typedef enum { battery_state_unknown = 0, battery_state_charging, battery_state_discharging, battery_state_empty, battery_state_fully, battery_state_pending_charge, battery_state_pending_discharge, battery_state_last } BatteryState; class UpowerBatteryDBus : public QObject { Q_OBJECT public: explicit UpowerBatteryDBus(int batteryId, const QString &batteryDBusPath, QObject *parent = nullptr); ~UpowerBatteryDBus(); private: void initBatteryInfo(); int m_batteryId; QString m_batteryDBusPath; QDBusInterface *m_DBusInterface; bool m_batteryPresent; double m_percentage; double m_energyNow; double m_energyFull; double m_energyFullDesign; Q_SIGNALS: void batteryInfoChanged(int, QStringList); private Q_SLOTS: void dealBatteryPropertiesMessage(QDBusMessage); public: bool batteryIsPresent(); double getBatteryPercentage(); double getEnergyNow(); double getEnergyFull(); double getEnergyFullDesign(); void refreshBatteryInfo(); }; #endif // UPOWERBATTERYDBUS_H ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upower-dbus/upowerdbus.h0000664000175000017500000000404515167661430030333 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPOWERDBUS_H #define UPOWERDBUS_H #include #include #include enum up_device_type { up_device_type_unknown = 0, up_device_type_line_power, up_device_type_battery, up_device_type_ups, up_device_type_monitor, up_device_type_mouse, up_device_type_keyboard, up_device_type_pda, up_device_type_phone, up_device_type_media_player, up_device_type_tablet, up_device_type_computer, up_device_type_max }; class UPowerDBus : public QObject { Q_OBJECT public: explicit UPowerDBus(QObject *parent = nullptr); ~UPowerDBus(); private: int getDeviceType(const QString &); void initDeviceInfo(); void dealLidClosedMessage(bool); void dealBatteryOnlineMessage(bool); QDBusInterface *m_DBusInterface; bool m_hasLid; bool m_lidIsClosed; bool m_batteryOnline; QString m_upowerDaemonVersion; QStringList m_batteryPathList; QStringList m_linePowerPathList; private Q_SLOTS: void dealUPowerDBusMessage(QDBusMessage); Q_SIGNALS: void lidStateChanged(bool); void batteryOnlineStateChanged(bool); public: bool hasLid(); bool getLidClosedState(); bool getBatteryOnlineState(); QString getUpowerDaemonVersion(); QStringList getBatteryPathList(); QStringList getLinePowerPathList(); }; #endif // UPOWERDBUS_H ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upower-dbus/upowerdbus.cpp0000664000175000017500000001113415167661430030663 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upowerdbus.h" UPowerDBus::UPowerDBus(QObject *parent) : QObject(parent) { m_DBusInterface = new QDBusInterface("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.DBus.Properties", QDBusConnection::systemBus()); QDBusConnection::systemBus().connect("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(dealUPowerDBusMessage(QDBusMessage))); QDBusInterface dBusInterface("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.UPower", QDBusConnection::systemBus()); QDBusReply> reply = dBusInterface.call("EnumerateDevices"); if (dBusInterface.isValid()) { for (QDBusObjectPath dBusObjectPath : reply.value()) { int upDeviceType = getDeviceType(dBusObjectPath.path()); if (up_device_type_line_power == upDeviceType) { m_linePowerPathList << dBusObjectPath.path(); } else if (up_device_type_battery == upDeviceType) { m_batteryPathList << dBusObjectPath.path(); } } } initDeviceInfo(); } UPowerDBus::~UPowerDBus() { delete m_DBusInterface; } int UPowerDBus::getDeviceType(const QString &dBusPath) { QDBusInterface dBusInterface("org.freedesktop.UPower", dBusPath, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus()); QDBusReply reply = dBusInterface.call("Get", "org.freedesktop.UPower.Device", "Type"); if (reply.isValid()) { return reply.value().toInt(); } else { return up_device_type_unknown; } } void UPowerDBus::initDeviceInfo() { QDBusMessage msg = m_DBusInterface->call("GetAll", "org.freedesktop.UPower"); if (msg.type() == QDBusMessage::ReplyMessage) { const QDBusArgument &dbusArgs = msg.arguments().at(0).value(); QMap map; dbusArgs >> map; m_hasLid = map.value(QString("LidIsPresent")).toBool(); m_lidIsClosed = map.value(QString("LidIsClosed")).toBool(); m_batteryOnline = map.value(QString("OnBattery")).toBool(); m_upowerDaemonVersion = map.value(QString("DaemonVersion")).toString(); } } void UPowerDBus::dealLidClosedMessage(bool value) { if (m_lidIsClosed != value) { m_lidIsClosed = value; Q_EMIT lidStateChanged(m_lidIsClosed); } } void UPowerDBus::dealBatteryOnlineMessage(bool value) { if (m_batteryOnline != value) { m_batteryOnline = value; emit batteryOnlineStateChanged(m_batteryOnline); } } void UPowerDBus::dealUPowerDBusMessage(QDBusMessage msg) { const QDBusArgument &dbusArgs = msg.arguments().at(1).value(); QMap map; dbusArgs >> map; if (map.contains("LidIsClosed")) { dealLidClosedMessage(map.value(QString("LidIsClosed")).toBool()); } if (map.contains("OnBattery")) { dealBatteryOnlineMessage(map.value(QString("OnBattery")).toBool()); } } bool UPowerDBus::hasLid() { return m_hasLid; } bool UPowerDBus::getLidClosedState() { return m_lidIsClosed; } bool UPowerDBus::getBatteryOnlineState() { return m_batteryOnline; } QString UPowerDBus::getUpowerDaemonVersion() { return m_upowerDaemonVersion; } QStringList UPowerDBus::getBatteryPathList() { return m_batteryPathList; } QStringList UPowerDBus::getLinePowerPathList() { return m_linePowerPathList; } ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upower-dbus/upowerbatterydbus.cpp0000664000175000017500000000760115167661430032262 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upowerbatterydbus.h" UpowerBatteryDBus::UpowerBatteryDBus(int batteryId, const QString &batteryDBusPath, QObject *parent) : QObject(parent), m_batteryId(batteryId), m_batteryDBusPath(batteryDBusPath) { m_DBusInterface = new QDBusInterface("org.freedesktop.UPower", m_batteryDBusPath, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus(), this); QDBusConnection::systemBus().connect("org.freedesktop.UPower", m_batteryDBusPath, "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(dealBatteryPropertiesMessage(QDBusMessage))); initBatteryInfo(); } UpowerBatteryDBus::~UpowerBatteryDBus() {} void UpowerBatteryDBus::dealBatteryPropertiesMessage(QDBusMessage msg) { const QDBusArgument &dbusArgs = msg.arguments().at(1).value(); QMap map; dbusArgs >> map; QStringList batteryInfoChangedList; if (map.contains("IsPresent")) { m_batteryPresent = map.value(QString("IsPresent")).toBool(); batteryInfoChangedList.append("IsPresent"); } if (map.contains("Percentage")) { m_percentage = map.value(QString("Percentage")).toDouble(); batteryInfoChangedList.append("Percentage"); } if (map.contains("Energy")) { m_energyNow = map.value(QString("Energy")).toDouble(); batteryInfoChangedList.append("Energy"); } if (0 != batteryInfoChangedList.size()) { emit batteryInfoChanged(m_batteryId, batteryInfoChangedList); } } void UpowerBatteryDBus::initBatteryInfo() { QDBusMessage msg = m_DBusInterface->call("GetAll", "org.freedesktop.UPower.Device"); if (msg.type() == QDBusMessage::ReplyMessage) { const QDBusArgument &dbusArgs = msg.arguments().at(0).value(); QMap map; dbusArgs >> map; m_batteryPresent = map.value(QString("IsPresent")).toBool(); m_percentage = map.value(QString("Percentage")).toDouble(); m_energyNow = map.value(QString("Energy")).toDouble(); m_energyFull = map.value(QString("EnergyFull")).toDouble(); m_energyFullDesign = map.value(QString("EnergyFullDesign")).toDouble(); } } bool UpowerBatteryDBus::batteryIsPresent() { return m_batteryPresent; } double UpowerBatteryDBus::getBatteryPercentage() { return m_percentage; } double UpowerBatteryDBus::getEnergyNow() { return m_energyNow; } double UpowerBatteryDBus::getEnergyFull() { return m_energyFull; } double UpowerBatteryDBus::getEnergyFullDesign() { return m_energyFullDesign; } void UpowerBatteryDBus::refreshBatteryInfo() { QDBusInterface dBusInterface("org.freedesktop.UPower", m_batteryDBusPath, "org.freedesktop.UPower.Device", QDBusConnection::systemBus()); dBusInterface.call("Refresh"); } ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upower-dbus/upm_upowerdbus.h0000664000175000017500000000376315167661430031222 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPM_UPOWERDBUS_H #define UPM_UPOWERDBUS_H #include #include "upowerdbus.h" #include "upowerbatterydbus.h" #include "upowerlinepowerdbus.h" class UpmUpowerDBus : public QObject { Q_OBJECT public: explicit UpmUpowerDBus(QObject *parent = nullptr); ~UpmUpowerDBus(); static UpmUpowerDBus* self(); void refreshBatteryInfo(); private: UPowerDBus *m_upowerDBus; QVector m_batteryDBusVector; QVector m_linePowerDBusVector; QString m_batteryIconName; signals: void lidStateChanged(bool); void batteryOnlineStateChanged(bool); void batteryInfoChanged(int, QStringList); void acOnlineStateChanged(int, bool); private: void dealLidStateChanged(bool); void dealBatteryOnlineStateChanged(bool); void dealBatteryInfoChanged(int, QStringList); void dealAcOnlineStateChanged(int, bool); public: bool getLidClosedState(); bool getBatteryOnlineState(); bool hasBattery(); bool batteryIsPresent(int index = 0); int getBatteryNum(); int getLinePowerNum(); double getBatteryPercentage(); double getEnergyNow(int index = 0); double getEnergyFull(int index = 0); double getEnergyFullDesign(int index = 0); bool getAcOnlineState(); }; #endif // UPM_UPOWERDBUS_H ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upower-dbus/upowerlinepowerdbus.h0000664000175000017500000000245415167661430032262 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPOWERLINEPOWERDBUS_H #define UPOWERLINEPOWERDBUS_H #include #include #include class UpowerLinePowerDBus : public QObject { Q_OBJECT public: explicit UpowerLinePowerDBus(int linePowerId, const QString &linePowerDBusPath, QObject *parent = nullptr); ~UpowerLinePowerDBus(); private: int m_linePowerId; QDBusInterface *m_DBusInterface; bool m_acOnlineState; Q_SIGNALS: void acOnlineStateChanged(int, bool); private Q_SLOTS: void dealLinePowerPropertiesMessage(QDBusMessage); public: int getAcOnlineState(); }; #endif // UPOWERLINEPOWERDBUS_H ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upower-dbus/upm_upowerdbus.cpp0000664000175000017500000001143515167661430031550 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "upm_upowerdbus.h" Q_GLOBAL_STATIC(UpmUpowerDBus, s_upowerDBus) UpmUpowerDBus::UpmUpowerDBus(QObject *parent) : QObject(parent) { m_upowerDBus = new UPowerDBus(this); connect(m_upowerDBus, &UPowerDBus::lidStateChanged, this, &UpmUpowerDBus::dealLidStateChanged); connect(m_upowerDBus, &UPowerDBus::batteryOnlineStateChanged, this, &UpmUpowerDBus::dealBatteryOnlineStateChanged); int index = 0; QStringList batteryPathList = m_upowerDBus->getBatteryPathList(); for (index = 0; index < batteryPathList.size(); ++index) { UpowerBatteryDBus *upowerBatteryDBus = new UpowerBatteryDBus(index, batteryPathList.at(index), this); connect(upowerBatteryDBus, &UpowerBatteryDBus::batteryInfoChanged, this, &UpmUpowerDBus::dealBatteryInfoChanged); m_batteryDBusVector << upowerBatteryDBus; } QStringList linePowerPathList = m_upowerDBus->getLinePowerPathList(); for (index = 0; index < linePowerPathList.size(); ++index) { UpowerLinePowerDBus *upowerLinePowerDBus = new UpowerLinePowerDBus(index, linePowerPathList.at(index), this); connect(upowerLinePowerDBus, &UpowerLinePowerDBus::acOnlineStateChanged, this, &UpmUpowerDBus::dealAcOnlineStateChanged); m_linePowerDBusVector << upowerLinePowerDBus; } } UpmUpowerDBus::~UpmUpowerDBus() {} UpmUpowerDBus *UpmUpowerDBus::self() { return s_upowerDBus; } void UpmUpowerDBus::refreshBatteryInfo() { for (int batteryNum = 0; batteryNum < m_batteryDBusVector.size(); ++batteryNum) { m_batteryDBusVector.at(batteryNum)->refreshBatteryInfo(); } } void UpmUpowerDBus::dealLidStateChanged(bool value) { emit lidStateChanged(value); } void UpmUpowerDBus::dealBatteryOnlineStateChanged(bool value) { emit batteryOnlineStateChanged(value); } void UpmUpowerDBus::dealBatteryInfoChanged(int index, QStringList batteryInfoChangedList) { emit batteryInfoChanged(index, batteryInfoChangedList); } void UpmUpowerDBus::dealAcOnlineStateChanged(int index, bool value) { emit acOnlineStateChanged(index, value); } bool UpmUpowerDBus::getLidClosedState() { return m_upowerDBus->getLidClosedState(); } bool UpmUpowerDBus::getBatteryOnlineState() { return m_upowerDBus->getBatteryOnlineState(); } bool UpmUpowerDBus::hasBattery() { if (0 == m_batteryDBusVector.size()) { return false; } for (int batteryNum = 0; batteryNum < m_batteryDBusVector.size(); ++batteryNum) { if (true == batteryIsPresent(batteryNum)) { return true; } } return false; } bool UpmUpowerDBus::batteryIsPresent(int index) { if (0 == m_batteryDBusVector.size()) { return false; } return m_batteryDBusVector.at(index)->batteryIsPresent(); } int UpmUpowerDBus::getBatteryNum() { return m_batteryDBusVector.size(); } int UpmUpowerDBus::getLinePowerNum() { return m_linePowerDBusVector.size(); } double UpmUpowerDBus::getBatteryPercentage() { if (0 == m_batteryDBusVector.size()) { return 0; } double percentage = 0.0; for (int index = 0; index < m_batteryDBusVector.size(); ++index) { percentage += m_batteryDBusVector.at(index)->getBatteryPercentage(); } return percentage / m_batteryDBusVector.size(); } double UpmUpowerDBus::getEnergyNow(int index) { if (0 == m_batteryDBusVector.size()) { return 0; } return m_batteryDBusVector.at(index)->getEnergyNow(); } double UpmUpowerDBus::getEnergyFull(int index) { if (0 == m_batteryDBusVector.size()) { return 0; } return m_batteryDBusVector.at(index)->getEnergyFull(); } double UpmUpowerDBus::getEnergyFullDesign(int index) { if (0 == m_batteryDBusVector.size()) { return 0; } return m_batteryDBusVector.at(index)->getEnergyFullDesign(); } bool UpmUpowerDBus::getAcOnlineState() { if (0 == m_batteryDBusVector.size() || 0 == m_linePowerDBusVector.size()) { return true; } for (int index = 0; index < m_linePowerDBusVector.size(); ++index) { if (true == m_linePowerDBusVector.at(index)->getAcOnlineState()) { return true; } } return false; } ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upttbatterydate.cpp0000664000175000017500000000330315167661430027434 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "upttbatterydate.h" #include UpttBatteryDate::UpttBatteryDate(qint64 percentage, double energyNow, QDateTime lastTime, double lastEnergy, QObject *parent) : QObject(parent) { m_recordDateTime = QDateTime::currentDateTime(); m_percentage = percentage; m_energyNow = energyNow; if (0 != lastEnergy) { m_elapsedTimeSecs = lastTime.secsTo(m_recordDateTime); double diffTimeHour = (double)m_elapsedTimeSecs / 3600; m_energyRate = (lastEnergy - m_energyNow) / diffTimeHour; } } UpttBatteryDate::~UpttBatteryDate() {} QDateTime UpttBatteryDate::getRecordDateTime() { return m_recordDateTime; } qint64 UpttBatteryDate::getBatteryPercentage() { return m_percentage; } qint64 UpttBatteryDate::getElapsedTime() { return m_elapsedTimeSecs; } double UpttBatteryDate::getBatteryEnergy() { return m_energyNow; } double UpttBatteryDate::getBatteryEnergyRate() { return m_energyRate; } ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upttruntestbutton.cpp0000664000175000017500000000757215167661430030100 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "upttruntestbutton.h" UpttRunTestButton::UpttRunTestButton(QWidget *parent) : QWidget(parent) { initRunTestButtonUI(); initAcOnlineHintTimer(); } UpttRunTestButton::~UpttRunTestButton() { if (nullptr != m_acOnlineHintTimer) { delete m_acOnlineHintTimer; } } void UpttRunTestButton::initRunTestButtonUI() { QHBoxLayout *mainLayout = new QHBoxLayout(this); m_runEnduranceTestButton = new QPushButton("续航测试", this); m_runEnergyRateTestButton = new QPushButton("功耗测试", this); m_stopTestButton = new QPushButton("停止测试", this); mainLayout->addStretch(); mainLayout->addWidget(m_runEnduranceTestButton); mainLayout->addWidget(m_runEnergyRateTestButton); mainLayout->addWidget(m_stopTestButton); connect(m_runEnduranceTestButton, &QPushButton::clicked, this, &UpttRunTestButton::dealRunEnduranceTestButtonClicked); connect(m_runEnergyRateTestButton, &QPushButton::clicked, this, &UpttRunTestButton::dealRunEnergyRateTestButtonClicked); connect(m_stopTestButton, &QPushButton::clicked, this, &UpttRunTestButton::dealStopTestButtonClicked); connect(UpmUpowerDBus::self(), &UpmUpowerDBus::acOnlineStateChanged, this, &UpttRunTestButton::dealAcOnlineStateChanged); } void UpttRunTestButton::initAcOnlineHintTimer() { m_acOnlineHintTimer = new QTimer(); connect(m_acOnlineHintTimer, &QTimer::timeout, this, &UpttRunTestButton::dealStopTestButtonClicked); } void UpttRunTestButton::stopTest() { dealStopTestButtonClicked(); } void UpttRunTestButton::dealRunEnduranceTestButtonClicked() { m_runEnduranceTestButton->setEnabled(false); m_runEnergyRateTestButton->setEnabled(false); if (true == UpmUpowerDBus::self()->getAcOnlineState()) { m_acOnlineHintTimer->start(60000); emit acOnlineTestNotRunSignal(); } else { emit runEnduranceTestSignal(); } m_testState = run_endurance_test; } void UpttRunTestButton::dealRunEnergyRateTestButtonClicked() { m_runEnduranceTestButton->setEnabled(false); m_runEnergyRateTestButton->setEnabled(false); if (true == UpmUpowerDBus::self()->getAcOnlineState()) { m_acOnlineHintTimer->start(60000); emit acOnlineTestNotRunSignal(); } else { emit runEnergyRateTestSignal(); } m_testState = run_energy_rate_test; } void UpttRunTestButton::dealStopTestButtonClicked() { if (true == m_acOnlineHintTimer->isActive()) { m_acOnlineHintTimer->stop(); } m_runEnduranceTestButton->setEnabled(true); m_runEnergyRateTestButton->setEnabled(true); m_testState = stop_test; emit stopTestSignal(); } void UpttRunTestButton::dealAcOnlineStateChanged() { if (true == UpmUpowerDBus::self()->getAcOnlineState()) { dealStopTestButtonClicked(); } else { if (true == m_acOnlineHintTimer->isActive()) { m_acOnlineHintTimer->stop(); if (run_endurance_test == m_testState) { emit runEnduranceTestSignal(); } else if (run_energy_rate_test == m_testState) { emit runEnergyRateTestSignal(); } else { ; } } } } ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/uptttestconfigpage.h0000664000175000017500000000620015167661430027572 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef UPTTTESTCONFIGPAGE_H #define UPTTTESTCONFIGPAGE_H #include #include #include #include #include #include #include #include #include #include #include #include "upttcpupolicyconfig.h" #include "upttbrightnessconfig.h" #include "upttruntestbutton.h" #include "upttbatterydate.h" #include "upower-dbus/upm_upowerdbus.h" #include "uptt-gsettings/upm_gsettings.h" #define UPM_DBUS_SERVICE "org.ukui.powermanagement" #define UPM_DBUS_PATH "/" #define UPM_DBUS_INTERFACE "org.ukui.powermanagement.interface" class UpttTestConfigPage : public QWidget { Q_OBJECT public: explicit UpttTestConfigPage(QWidget *parent = nullptr); ~UpttTestConfigPage(); void initUpttTestConfigPage(); private: UpttCpuPolicyConfig *m_upttCpuPolicyConfig; UpttBrightnessConfig *m_upttBrightnessConfig; QCheckBox *m_balanceModeReduceFrequency; QCheckBox *m_autoSwitchCpuCore; QCheckBox *m_idleReserveCpu0; QCheckBox *m_idleReduceBrightness; QCheckBox *m_idleTurnoffDisplay; QCheckBox *m_idleSystemSuspend; QCheckBox *m_disableScreenSaver; QCheckBox *m_idlePowerPolicyAuto; QCheckBox *m_criticalPercentageDoNothing; UpttRunTestButton *m_runTestButton; QLabel *m_hintMessage; int m_cpuCoreNum = 0; enum test_type { unknown_test, endurance_test, energy_rate_test }; bool m_testIsRunning = false; int m_testType = unknown_test; bool m_refreshBatteryInfo = false; QDateTime m_runTestDateTime; double m_energyNow; double m_energyFull; double m_energyFullDesign; double m_batteryHealth; quint64 m_startBrightness; quint64 m_stopBrightness; QVector m_batteryDateVector; int m_minBatteryPercentage; QTimer *m_energyRateTestTimer = nullptr; QString m_testReportDir; bool m_hasNewReport = false; void initTestConfigPageUI(); void setTestConfig(); void createReportPath(); void createEnduranceTestReport(); void createEnergyRateTestReport(); void clearBatteryDate(); QString secondsToTimeFormat(int seconds); private slots: void runEnduranceTest(); void runEnergyRateTest(); void stopTest(); void acOnlineTestNotRun(); void recordBatteryDate(int , QStringList); void dealEnergyRateTestTimer(); }; #endif // UPTTTESTCONFIGPAGE_H ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/uptt-gsettings/0000775000175000017500000000000015167661430026505 5ustar fengfengukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/uptt-gsettings/upm_gsettings.h0000664000175000017500000000600615167661430031550 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef UPM_GSETTINGS_H #define UPM_GSETTINGS_H #include #include #include #include //power gsettings 配置 #define POWER_MANAGER_SETTINGS "org.ukui.power-manager" //电源策略(0:节能 1:平衡 2:性能) #define GSETTINGS_KEY_POWER_POLICY_BATTERY "powerPolicyBattery" //空闲关闭显示器 #define GSETTINGS_KEY_SLEEP_DISPLAY_AC "sleepDisplayAc" #define GSETTINGS_KEY_SLEEP_DISPLAY_BATTERY "sleepDisplayBattery" //空闲睡眠 #define GSETTINGS_KEY_SLEEP_COMPUTER_AC "sleepComputerAc" #define GSETTINGS_KEY_SLEEP_COMPUTER_BATTERY "sleepComputerBattery" //空闲降低屏幕亮度 #define GSETTINGS_KEY_IDLE_BRIGHTNESS "idleBrightness" //空闲状态亮度,降低为当前值的百分之多少 //空闲时切换电源策略 #define GSETTINGS_KEY_IDLE_POWER_POLICY_AUTO "idlePowerPolicyAuto" //极低电量 #define GSETTINGS_KEY_PERCENTAGE_ACTION "percentageAction" //极低电量时执行 #define GSETTINGS_KEY_ACTION_CRITICAL_BATTERY "actionCriticalBattery" //亮度值 #define GSETTINGS_KEY_BRIGHTNESS_AC "brightnessAc" //screensaver gsettings 配置 #define SCREEN_SAVER_SETTINGS "org.ukui.screensaver" #define GSETTINGS_KEY_IDLE_DELAY "idleDelay" //usd gsettings 配置 #define USD_AUTO_BRIGHTENSS_SETTINGS "org.ukui.SettingsDaemon.plugins.auto-brightness" #define GSETTINGS_KEY_AUTO_BRIGHTENSS "autoBrightness" class UpmGsettings : public QObject { Q_OBJECT public: explicit UpmGsettings(QObject *parent = nullptr); ~UpmGsettings(); static UpmGsettings* self(); typedef void (UpmGsettings::*pSignalFun)(QVariant); private: QGSettings *m_powerGsettings; QStringList m_allPowerKey; QGSettings *m_screensaverGsettings; QStringList m_allScreensaverKey; QGSettings *m_usdAutoBrightnessGsettings; QStringList m_allUsdAutoBrightnessKey; QHash m_qHashValue; QHash m_qHashSignalsFuns; void initGsettingsConfig(); void addConfigMonitor(const QString &configName, pSignalFun signalFun); signals: public: void setGsettingsConfig(const QString &configName, QVariant value); bool getGsettingsConfig(const QString &configName, QVariant &value); void resetGsettingsConfig(const QString &configName); }; #endif // UPM_GSETTINGS_H ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/uptt-gsettings/upm_gsettings.cpp0000664000175000017500000001006515167661430032103 0ustar fengfeng/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "upm_gsettings.h" #include Q_GLOBAL_STATIC(UpmGsettings, s_upmGsettings) UpmGsettings::UpmGsettings(QObject *parent) : QObject(parent) { const QByteArray powerGsettingsID(POWER_MANAGER_SETTINGS); m_powerGsettings = new QGSettings(powerGsettingsID); m_allPowerKey = m_powerGsettings->keys(); const QByteArray processGsettingsID(SCREEN_SAVER_SETTINGS); m_screensaverGsettings = new QGSettings(processGsettingsID); m_allScreensaverKey = m_screensaverGsettings->keys(); const QByteArray usdAutoBrightnessGsettingsID(USD_AUTO_BRIGHTENSS_SETTINGS); m_usdAutoBrightnessGsettings = new QGSettings(usdAutoBrightnessGsettingsID); m_allUsdAutoBrightnessKey = m_usdAutoBrightnessGsettings->keys(); initGsettingsConfig(); } UpmGsettings::~UpmGsettings() { delete m_powerGsettings; delete m_screensaverGsettings; delete m_usdAutoBrightnessGsettings; } UpmGsettings *UpmGsettings::self() { return s_upmGsettings; } void UpmGsettings::setGsettingsConfig(const QString &configName, QVariant value) { if (true == m_qHashValue.contains(configName)) { m_qHashValue[configName] = value; if (m_allPowerKey.contains(configName)) { m_powerGsettings->set(configName, value); } else if (m_allScreensaverKey.contains(configName)) { m_screensaverGsettings->set(configName, value); } else if (m_allUsdAutoBrightnessKey.contains(configName)) { m_usdAutoBrightnessGsettings->set(configName, value); } } } bool UpmGsettings::getGsettingsConfig(const QString &configName, QVariant &value) { if (true == m_qHashValue.contains(configName)) { value = m_qHashValue[configName]; return true; } return false; } void UpmGsettings::resetGsettingsConfig(const QString &configName) { if (true == m_qHashValue.contains(configName)) { if (m_allPowerKey.contains(configName)) { m_powerGsettings->reset(configName); } else if (m_allScreensaverKey.contains(configName)) { m_screensaverGsettings->reset(configName); } else if (m_allUsdAutoBrightnessKey.contains(configName)) { m_usdAutoBrightnessGsettings->reset(configName); } } } void UpmGsettings::addConfigMonitor(const QString &configName, pSignalFun signalFun) { if (m_allPowerKey.contains(configName)) { m_qHashValue[configName] = m_powerGsettings->get(configName); } else if (m_allScreensaverKey.contains(configName)) { m_qHashValue[configName] = m_screensaverGsettings->get(configName); } else if (m_allUsdAutoBrightnessKey.contains(configName)) { m_qHashValue[configName] = m_usdAutoBrightnessGsettings->get(configName); } else { ; } } void UpmGsettings::initGsettingsConfig() { addConfigMonitor(GSETTINGS_KEY_POWER_POLICY_BATTERY, NULL); addConfigMonitor(GSETTINGS_KEY_SLEEP_DISPLAY_BATTERY, NULL); addConfigMonitor(GSETTINGS_KEY_SLEEP_COMPUTER_BATTERY, NULL); addConfigMonitor(GSETTINGS_KEY_IDLE_BRIGHTNESS, NULL); addConfigMonitor(GSETTINGS_KEY_IDLE_POWER_POLICY_AUTO, NULL); addConfigMonitor(GSETTINGS_KEY_PERCENTAGE_ACTION, NULL); addConfigMonitor(GSETTINGS_KEY_ACTION_CRITICAL_BATTERY, NULL); addConfigMonitor(GSETTINGS_KEY_BRIGHTNESS_AC, NULL); addConfigMonitor(GSETTINGS_KEY_IDLE_DELAY, NULL); addConfigMonitor(GSETTINGS_KEY_AUTO_BRIGHTENSS, NULL); } ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upttbatterydate.h0000664000175000017500000000263515167661430027110 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef UPTTBATTERYDATE_H #define UPTTBATTERYDATE_H #include #include #include class UpttBatteryDate : public QObject { Q_OBJECT public: explicit UpttBatteryDate(qint64 percentage, double energyNow, QDateTime lastTime, double lastEnergy, QObject *parent = nullptr); ~UpttBatteryDate(); QDateTime getRecordDateTime(); qint64 getBatteryPercentage(); qint64 getElapsedTime(); double getBatteryEnergy(); double getBatteryEnergyRate(); private: QDateTime m_recordDateTime; qint64 m_elapsedTimeSecs; qint64 m_percentage; double m_energyNow; double m_energyRate; }; #endif // UPTTBATTERYDATE_H ukui-power-manager/PowerManagementDaemon/ukui-power-test-tool/upttcpupolicyconfig.cpp0000664000175000017500000000343115167661430030323 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "upttcpupolicyconfig.h" #include UpttCpuPolicyConfig::UpttCpuPolicyConfig(QWidget *parent) : QWidget(parent) { QHBoxLayout *mainLayout = new QHBoxLayout(this); m_policyLabel = new QLabel("工作模式:", this); m_policyLabel->setContentsMargins(0, 0, 30, 0); m_policyGroup = new QButtonGroup(this); m_performanceRadio = new QRadioButton("性能模式", this); m_balanceRadio = new QRadioButton("平衡模式", this); m_powersaveRadio = new QRadioButton("节能模式", this); m_powersaveRadio->setChecked(true); m_policyGroup->addButton(m_performanceRadio, 0); m_policyGroup->addButton(m_balanceRadio, 1); m_policyGroup->addButton(m_powersaveRadio, 2); mainLayout->setSpacing(20); mainLayout->addWidget(m_policyLabel); mainLayout->addWidget(m_performanceRadio); mainLayout->addWidget(m_balanceRadio); mainLayout->addWidget(m_powersaveRadio); mainLayout->addStretch(); } UpttCpuPolicyConfig::~UpttCpuPolicyConfig() {} int UpttCpuPolicyConfig::getPowerPolicyBattery() { return m_policyGroup->checkedId(); } ukui-power-manager/PowerManagementDaemon/gsettingwatcher/0000775000175000017500000000000015167661430022647 5ustar fengfengukui-power-manager/PowerManagementDaemon/gsettingwatcher/gsettingwatcher.cpp0000664000175000017500000002155615167661430026566 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "gsettingwatcher.h" GsettingWatcher::GsettingWatcher() { QString cpuType = getCpuInfo(); m_isIntel = cpuType.contains("intel",Qt::CaseInsensitive); if (m_isIntel) { qDebug() << "use tlp:" << cpuType; } else { qDebug() << "don;t use tlp:" << cpuType; } m_ptlpTimer = new QTimer(this); m_ptlpTimer->setSingleShot(true); connect(m_ptlpTimer, &QTimer::timeout, this, &GsettingWatcher::setTlp); } GsettingWatcher::~GsettingWatcher() {} void GsettingWatcher::initGsettingWatcher() { mAcWatcher.initAcWatcher(); initSettingsConnect(); initLowPowerAutoSave(); } void GsettingWatcher::initSettingsConnect() { mPowerPolicyAc = m_powerManagerGsettings->get(POWER_POLICY_AC).toInt(); mPowerPolicyBattery = m_powerManagerGsettings->get(POWER_POLICY_BATTERY).toInt(); if (false == mAcWatcher.mPowerState) { policyAC(); } else { policyBattery(); } connect(m_powerManagerGsettings, &QGSettings::changed, this, [=](const QString &key) { if (key == POWER_POLICY_AC) { mPowerPolicyAc = m_powerManagerGsettings->get(POWER_POLICY_AC).toInt(); if (false == mAcWatcher.mPowerState) { policyAC(); } } if (key == POWER_POLICY_BATTERY) { mPowerPolicyBattery = m_powerManagerGsettings->get(POWER_POLICY_BATTERY).toInt(); if (true == mAcWatcher.mPowerState) { policyBattery(); if (EnergySaving != mPowerPolicyBattery && Unknow != m_powerPolicyBatteryBackup) { m_powerPolicyBatteryBackup = Unknow; m_powerManagerGsettings->set(POWER_POLICY_BATTERY_BACKUP, Unknow); } } } }); connect(&mAcWatcher, SIGNAL(acChanged(bool)), this, SLOT(AcWatcherChanged(bool))); } void GsettingWatcher::AcWatcherChanged(const bool &onBattery) { if (false == onBattery) { policyAC(); setLowPowerState(false); } else { if (m_percentageLow >= m_batteryPercentage) { setLowPowerState(true); } else { policyBattery(); } } } void GsettingWatcher::setLowPowerState(bool lowPowerState) { if (mLowPrecentState == lowPowerState) { return; } if (true == lowPowerState) { if (1 == mLowBatteryAutoSave) { if (Unknow == m_powerPolicyBatteryBackup) { m_powerPolicyBatteryBackup = mPowerPolicyBattery; m_powerManagerGsettings->set(POWER_POLICY_BATTERY, EnergySaving); m_powerManagerGsettings->set(POWER_POLICY_BATTERY_BACKUP, m_powerPolicyBatteryBackup); qInfo() << "battery policy backup:" << m_powerPolicyBatteryBackup; } } } else { resetPowerPolicyBatteryBackup(); qDebug() << "exit low battery mode"; } mLowPrecentState = lowPowerState; } void GsettingWatcher::initLowPowerAutoSave() { mLowBatteryAutoSave = m_powerManagerGsettings->get(LOW_BATTERY_ATUO_SAVE).toInt(); m_powerPolicyBatteryBackup = m_powerManagerGsettings->get(POWER_POLICY_BATTERY_BACKUP).toInt(); m_percentageLow = m_powerManagerGsettings->get(PERCENTAGE_LOW).toInt(); QDBusInterface dBusInterface(UPOWER_SERVICE, UPOWER_DISPLAY_PATH, FREEDESKTOP_UPOWER, QDBusConnection::systemBus()); QDBusReply reply = dBusInterface.call("Get", "org.freedesktop.UPower.Device", "Percentage"); if (reply.isValid()) { m_batteryPercentage = reply.value().toDouble(); } else { qDebug() << "get power percentage failed!"; m_batteryPercentage = 0; } if (true == mAcWatcher.mPowerState) { if (m_percentageLow >= m_batteryPercentage) { setLowPowerState(true); } else { resetPowerPolicyBatteryBackup(); } } else { resetPowerPolicyBatteryBackup(); } connect(m_powerManagerGsettings, &QGSettings::changed, this, [=](const QString &key) { if (key == LOW_BATTERY_ATUO_SAVE) { mLowBatteryAutoSave = m_powerManagerGsettings->get(LOW_BATTERY_ATUO_SAVE).toInt(); if (1 == mLowBatteryAutoSave) { if (true == mLowPrecentState) { m_powerPolicyBatteryBackup = mPowerPolicyBattery; m_powerManagerGsettings->set(POWER_POLICY_BATTERY, EnergySaving); } } else { if (true == mLowPrecentState) { m_powerPolicyBatteryBackup = Unknow; } } m_powerManagerGsettings->set(POWER_POLICY_BATTERY_BACKUP, m_powerPolicyBatteryBackup); } if (key == PERCENTAGE_LOW) { m_percentageLow = m_powerManagerGsettings->get(PERCENTAGE_LOW).toInt(); if (true == mAcWatcher.mPowerState) { if (m_percentageLow >= m_batteryPercentage) { setLowPowerState(true); } else { setLowPowerState(false); } } } }); QDBusConnection::systemBus().connect( UPOWER_SERVICE, UPOWER_DISPLAY_PATH, FREEDESKTOP_UPOWER, "PropertiesChanged", this, SLOT(dealBatteryPropertiesMessage(QDBusMessage))); } void GsettingWatcher::resetPowerPolicyBatteryBackup() { if (Unknow != m_powerPolicyBatteryBackup) { m_powerManagerGsettings->set(POWER_POLICY_BATTERY, m_powerPolicyBatteryBackup); m_powerPolicyBatteryBackup = Unknow; m_powerManagerGsettings->set(POWER_POLICY_BATTERY_BACKUP, m_powerPolicyBatteryBackup); } } void GsettingWatcher::dealBatteryPropertiesMessage(QDBusMessage msg) { const QDBusArgument &dbusArgs = msg.arguments().at(1).value(); QMap map; dbusArgs >> map; if (map.contains("Percentage")) { int batteryPercentage = map.value(QString("Percentage")).toDouble(); if (m_batteryPercentage != batteryPercentage) { m_batteryPercentage = batteryPercentage; if (true == mAcWatcher.mPowerState) { if (m_percentageLow >= m_batteryPercentage) { setLowPowerState(true); } } } } } void GsettingWatcher::setTlp() { if (!m_isIntel) { return; } if (m_isTlp) { controlPowerManagement(ENTER_TLP); } else { controlPowerManagement(EXIT_TLP); } } QString GsettingWatcher::getCpuInfo() { QFile file("/proc/cpuinfo"); if (file.open(QIODevice::ReadOnly)) { QString buffer = file.readAll(); QStringList modelLine = buffer.split('\n').filter(QRegularExpression("^model name")); QStringList modelLineWayland = buffer.split('\n').filter(QRegularExpression("^Hardware")); if (modelLine.isEmpty()) { if (modelLineWayland.isEmpty()) { return "Unknown"; } modelLine = modelLineWayland; } QString result; result.append(modelLine.first().split(':').at(1)); result = result.trimmed(); return result; } return QString(); } void GsettingWatcher::delayStartTlp(bool state) { if (m_isTlp != state) { m_isTlp = state; m_ptlpTimer->start(TLP_TIMER); } } void GsettingWatcher::policyAC() { delayStartTlp(false); controlPowerManagement(CPU_FREQENCY_MODULATION, mPowerPolicyAc); controlPowerManagement(GPU_FREQENCY_MODULATION, mPowerPolicyAc); controlPowerManagement(SET_AUDIO_MODE, mPowerPolicyAc); controlPowerManagement(SET_PCIE_ASPM_MODE, mPowerPolicyAc); m_powerManagerGsettings->set(POWER_POLICY_CURRENT, mPowerPolicyAc); } void GsettingWatcher::policyBattery() { controlPowerManagement(CPU_FREQENCY_MODULATION, mPowerPolicyBattery); controlPowerManagement(GPU_FREQENCY_MODULATION, mPowerPolicyBattery); controlPowerManagement(SET_AUDIO_MODE, mPowerPolicyBattery); controlPowerManagement(SET_PCIE_ASPM_MODE, mPowerPolicyBattery); m_powerManagerGsettings->set(POWER_POLICY_CURRENT, mPowerPolicyBattery); if (mPowerPolicyBattery == EnergySaving) { delayStartTlp(true); } else { delayStartTlp(false); } } ukui-power-manager/PowerManagementDaemon/gsettingwatcher/gsettingwatcher.h0000664000175000017500000000361615167661430026230 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GSETTINGWATCHER_H #define GSETTINGWATCHER_H #include #include "eventwatcher.h" #include "acwatcher/acwatcher.h" #include "lowpowerwatcher/lowpowerwatcher.h" class GsettingWatcher : public EventWatcher { Q_OBJECT public: GsettingWatcher(); ~GsettingWatcher(); void initGsettingWatcher(); private: enum policy { Performance = 0, Balance, EnergySaving, Unknow, }; void initSettingsConnect(); void policyAC(); void policyBattery(); int mPowerPolicyAc; int mPowerPolicyBattery; int mLowBatteryAutoSave; bool mLowPrecentState = false; AcWatcher mAcWatcher; int m_powerPolicyBatteryBackup = Unknow; int m_batteryPercentage; int m_percentageLow; bool m_isIntel = false; bool m_isTlp = false; QTimer *m_ptlpTimer = nullptr; private slots: void AcWatcherChanged(const bool &onBattery); void setLowPowerState(bool lowPowerState); void initLowPowerAutoSave(); void resetPowerPolicyBatteryBackup(); void dealBatteryPropertiesMessage(QDBusMessage msg); void setTlp(); private: QString getCpuInfo(); void delayStartTlp(bool state); }; #endif // GSETTINGWATCHER_H ukui-power-manager/registeredQDbus/0000775000175000017500000000000015167661430016324 5ustar fengfengukui-power-manager/registeredQDbus/brightness-control/0000775000175000017500000000000015167661430022152 5ustar fengfengukui-power-manager/registeredQDbus/brightness-control/brightnessnode.cpp0000664000175000017500000001573115167661430025703 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "brightnessnode.h" #include "hardware-reader/hardwarereader.h" #include "dmi_chassis_type.h" /* * 根据笔记本概率性无法设置亮度的问题,由于使用log5qt的机制,无法记录提权 * 进程的日志,暂时无法分析,只能根据最大亮度为0,以及不支持设置亮度的情况。 * 制定如下策略: * 1.先判断设备是否支持亮度。 * 2.读取设备的亮度信息。 * 3.如果支持亮度,但是亮度读取失败则重试若干次。 */ BrightnessNode::BrightnessNode(QObject *parent) : m_maxbrightness(0), m_hasEffectiveNode(false), m_isBrightnessEnhancementSupported(false), QObject(parent) { m_isCanAdjustBright = isBrightnessAdjustable(); if (true == m_isCanAdjustBright) { QString brightnessNode = UpmCustomHardwareConfig::self()->getBrightnessNode(); initBrightnessNodeInfo(brightnessNode); initBrightnessEnhancementCapability(); if (0 >= m_maxbrightness) { m_BrightnessTimer = new QTimer(this); m_BrightnessTimer->setSingleShot(false); QObject::connect(m_BrightnessTimer, &QTimer::timeout, this, &BrightnessNode::onBrightnessTimeOut); m_BrightnessTimer->start(1000); } } } BrightnessNode::~BrightnessNode() {} void BrightnessNode::initBrightnessNodeInfo(QString &brightnessNode) { QDir brightnessNodeDir(BRIGHTNESS_NODE_PATH); static QMap nodeTypeMap; if (!brightnessNode.isNull()) { m_effectiveNodePath = BRIGHTNESS_NODE_PATH + brightnessNode; if (!QFileInfo::exists(m_effectiveNodePath)) { qWarning() << "the configured brightness node does not exist:" << m_effectiveNodePath; m_hasEffectiveNode = false; return; } m_hasEffectiveNode = true; m_maxbrightness = getBrightnessNodeFileContent(m_effectiveNodePath, "/max_brightness").toInt(); if (0 < m_maxbrightness) { return; } qWarning() << "max brightness get error!"; } m_nodeDirs.clear(); m_nodeDirs = brightnessNodeDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); for (int i = 0; i < m_nodeDirs.size(); ++i) { nodeTypeMap.insert(getBrightnessNodeFileContent(BRIGHTNESS_NODE_PATH + m_nodeDirs.at(i), "/type"), BRIGHTNESS_NODE_PATH + m_nodeDirs.at(i)); } qWarning() << "all nodeDir" << nodeTypeMap; QStringList nodeTypes = {"firmware", "platform", "raw"};//优先级. for (int i = 0; i < nodeTypes.size(); ++i) { if (nodeTypeMap.keys().contains(nodeTypes[i])) { m_effectiveNodePath = nodeTypeMap[nodeTypes[i]]; m_hasEffectiveNode = true; m_maxbrightness = getBrightnessNodeFileContent(m_effectiveNodePath, "/max_brightness").toInt(); break; } } } bool BrightnessNode::isBrightnessAdjustable() { QFile file("/sys/class/dmi/id/chassis_type"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "Failed to open chassis_type file"; return false; } QString chassisTypeStr = file.readAll().trimmed(); file.close(); bool ok = false; int chassisTypeInt = chassisTypeStr.toInt(&ok); if (!ok) { qWarning() << "Invalid chassis_type format:" << chassisTypeStr; return false; } switch (static_cast(chassisTypeInt)) { case DmiChassisType::Laptop: case DmiChassisType::Notebook: case DmiChassisType::AllInOne: case DmiChassisType::Tablet: case DmiChassisType::Convertible: case DmiChassisType::Detachable: return true; default: qDebug() << "Device type not supported for brightness:" << chassisTypeInt; return false; } } QString BrightnessNode::getBrightnessNodeFileContent(const QString &strNodePath, const QString &strNodeFile) { QFile nodeFile(strNodePath + strNodeFile); if (!nodeFile.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "open file error :" << strNodePath + strNodeFile; return ""; } QString fileContent = nodeFile.readLine(); nodeFile.close(); qWarning() << "read" << nodeFile.fileName() << fileContent; return fileContent.remove('\n'); } bool BrightnessNode::canSetBrightness() { return m_isCanAdjustBright; } int BrightnessNode::getMaxBrightness() { return m_maxbrightness; } int BrightnessNode::getCurrentBrightness() { return getBrightnessNodeFileContent(m_effectiveNodePath, "/brightness").toInt(); } QString BrightnessNode::setCurrentBrightness(int iBrightness) { if (false == m_hasEffectiveNode) { return "no effective node"; } QFile brightnessFile(m_effectiveNodePath + "/brightness"); if (!brightnessFile.open(QIODevice::WriteOnly | QIODevice::Text)) { return "false"; } QTextStream in(&brightnessFile); in << iBrightness << Qt::endl; brightnessFile.close(); return QString("%1 set brightness %2").arg(m_effectiveNodePath).arg(iBrightness); } void BrightnessNode::onBrightnessTimeOut() { static QString brightnessNode = UpmCustomHardwareConfig::self()->getBrightnessNode(); static int getBrightnessNodeTimes = 0; initBrightnessNodeInfo(brightnessNode); qWarning() << "node path :" << m_effectiveNodePath; if (getBrightnessNodeTimes++ > 3 || true == m_hasEffectiveNode || m_maxbrightness > 0) { qWarning()<<"effectNode"<stop(); } } bool BrightnessNode::isBrightnessEnhancementSupported() { return m_isBrightnessEnhancementSupported; } void BrightnessNode::initBrightnessEnhancementCapability() { // BrightnessEnhancement‌ 判断是否支持亮度增强 const QStringList bn_enhancementSupported = {"LXKT-FTD3-X1", "LXKT-FTD3-N8"}; if (m_isCanAdjustBright && bn_enhancementSupported.contains(HardwareReader::instance()->getDMIInfo("board_name"), Qt::CaseInsensitive) && EdidComparator::isSameScreen()) { m_isBrightnessEnhancementSupported = true; qInfo() << "brightness enhancement supported and maxBrightness =" << m_maxbrightness; } }ukui-power-manager/registeredQDbus/brightness-control/brightnessnode.h0000664000175000017500000000335415167661430025346 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BRIGHTNESSNODE_H #define BRIGHTNESSNODE_H #include #include #include "../upmcustomhardwareconfig.h" #define BRIGHTNESS_NODE_PATH "/sys/class/backlight/" class BrightnessNode : public QObject { Q_OBJECT public: explicit BrightnessNode(QObject *parent = nullptr); ~BrightnessNode(); private: bool m_hasEffectiveNode; int m_maxbrightness; bool m_isCanAdjustBright; bool m_isBrightnessEnhancementSupported; QStringList m_nodeDirs; QString m_effectiveNodePath; QTimer *m_BrightnessTimer = nullptr; void initBrightnessNodeInfo(QString &brightnessNode); QString getBrightnessNodeFileContent(const QString &strNodePath, const QString &strNodeFile); bool isBrightnessAdjustable(); void initBrightnessEnhancementCapability(); public: bool canSetBrightness(); int getMaxBrightness(); int getCurrentBrightness(); bool isBrightnessEnhancementSupported(); QString setCurrentBrightness(int iBrightness); private Q_SLOTS: void onBrightnessTimeOut(); }; #endif // BRIGHTNESSNODE_H ukui-power-manager/registeredQDbus/powerconfig.h0000664000175000017500000000540015167661430021016 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef POWERCONFIG_H #define POWERCONFIG_H #include #include #include #define POWER_MANAGER_CONF_PATH "/etc/power/power-manager.conf" #define POWER_MANAGER_NO_THIS_KEY "no-this-key" #define CONFIG_GROUP_CONFIG "config" #define POWER_MANAGER_RUN_TIMES "powerManagerRunTimes" //电源策略(0:节能 1:平衡 2:性能) #define GSETTINGS_KEY_POWER_POLICY_AC "powerPolicyAc" #define GSETTINGS_KEY_POWER_POLICY_BATTERY "powerPolicyBattery" #define GSETTINGS_KEY_POWER_POLICY_BATTERY_BACKUP "powerPolicyBatteryBackup" //空闲关闭显示器 #define GSETTINGS_KEY_SLEEP_DISPLAY_AC "sleepDisplayAc" #define GSETTINGS_KEY_SLEEP_DISPLAY_BATTERY "sleepDisplayBattery" //空闲睡眠 #define GSETTINGS_KEY_SLEEP_COMPUTER_AC "sleepComputerAc" #define GSETTINGS_KEY_SLEEP_COMPUTER_BATTERY "sleepComputerBattery" //盒盖事件触发操作 #define GSETTINGS_KEY_BUTTON_LID_AC "buttonLidAc" #define GSETTINGS_KEY_BUTTON_LID_BATTERY "buttonLidBattery" //低电量百分百通知 #define GSETTINGS_KEY_PERCENTAGE_LOW "percentageLow" //极低电量 #define GSETTINGS_KEY_PERCENTAGE_ACTION "percentageAction" //极低电量时执行 #define GSETTINGS_KEY_ACTION_CRITICAL_BATTERY "actionCriticalBattery" //低电量时自动开启节能模式 #define GSETTINGS_KEY_BATTERY_SAVE_SWITCH "batterySaveSwitch" //低电量时自动开启节能模式 #define GSETTINGS_KEY_LOW_BATTERY_AUTO_SAVE "lowBatteryAutoSave" //节能模式降低亮度 #define GSETTINGS_KEY_BATTERY_SAVE_REDUCE_BRIGHTNESS "batterySaveReduceBrightness" //亮度值 #define GSETTINGS_KEY_BRIGHTNESS_AC "brightnessAc" class PowerConfig : public QObject { Q_OBJECT public: explicit PowerConfig(QObject *parent = nullptr); ~PowerConfig(); int getPowerManagerRunTimes(); void updatePowerConfig(const QString &key, const QString &value); bool getPowerConfig(const QString &key, QVariant &value); private: int m_powerManagerRunTimes = 0; QSettings *m_qsettings; signals: }; #endif // POWERCONFIG_H ukui-power-manager/registeredQDbus/upmcommonfile.h0000664000175000017500000000223415167661430021350 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPMCOMMONFILE_H #define UPMCOMMONFILE_H #include class UpmCommonFile : public QObject { Q_OBJECT public: explicit UpmCommonFile(QObject *parent = nullptr); static bool read(const QString &filePath, const QString &fileName, QString &content); static bool write(const QString &filePath, const QString &fileName, const QString &content); static bool exists(const QString &filePath, const QString &fileName); signals: }; #endif // UPMCOMMONFILE_H ukui-power-manager/registeredQDbus/cpu-control/0000775000175000017500000000000015167661430020571 5ustar fengfengukui-power-manager/registeredQDbus/cpu-control/upmcpuoccupy.h0000664000175000017500000000314015167661430023474 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPMCPUOCCUPY_H #define UPMCPUOCCUPY_H #include #include #define CPU_PROC_PATH "/proc/" #define CPU_PROC_STATE "stat" #define MIN_OFFLINE_CPU_OCCUPY 25 #define MAX_ONLINE_CPU_OCCUPY 85 #define MIN_CPU_OCCUPY_INTERVAL 10 class UpmCpuOccupy : public QObject { Q_OBJECT public: explicit UpmCpuOccupy(QObject *parent = nullptr); void startCalcCpuOccupy(int timeout, int offlineCpuOccupy, int onlineCpuOccupy); void stopCalcCpuOccupy(); private: QTimer *m_calcCpuOccupyTimer; quint64 m_currentTotalTime = 0; quint64 m_currentUserTime = 0; quint64 m_lastTotalTime = 0; quint64 m_lastUserTime = 0; int m_offlineCpuOccupy = 0; int m_onlineCpuOccupy = 0; void getCpuOccupyTime(quint64 &totalTime, quint64 &userTime); private slots: void calcCpuOccupy(); signals: void cpuCoreSwitchSignal(bool); }; #endif // UPMCPUOCCUPY_H ukui-power-manager/registeredQDbus/cpu-control/upmcpuoccupy.cpp0000664000175000017500000000570315167661430024036 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upmcpuoccupy.h" #include "../upmcommonfile.h" #include UpmCpuOccupy::UpmCpuOccupy(QObject *parent) : QObject(parent) { m_calcCpuOccupyTimer = new QTimer(this); connect(m_calcCpuOccupyTimer, &QTimer::timeout, this, &UpmCpuOccupy::calcCpuOccupy); } void UpmCpuOccupy::startCalcCpuOccupy(int timeout, int offlineCpuOccupy, int onlineCpuOccupy) { if (timeout < 10000 || offlineCpuOccupy < MIN_OFFLINE_CPU_OCCUPY || onlineCpuOccupy > MAX_ONLINE_CPU_OCCUPY) { return ; } if (offlineCpuOccupy > onlineCpuOccupy || onlineCpuOccupy - offlineCpuOccupy < MIN_CPU_OCCUPY_INTERVAL) { return ; } qDebug() << "start calc cpu occupy:" << timeout << offlineCpuOccupy << onlineCpuOccupy; m_offlineCpuOccupy = offlineCpuOccupy; m_onlineCpuOccupy = onlineCpuOccupy; getCpuOccupyTime(m_lastTotalTime, m_lastUserTime); qDebug() << "init cpu time:" << m_lastTotalTime << m_lastUserTime; m_calcCpuOccupyTimer->start(timeout); } void UpmCpuOccupy::stopCalcCpuOccupy() { if (m_calcCpuOccupyTimer->isActive()) { m_calcCpuOccupyTimer->stop(); } } void UpmCpuOccupy::calcCpuOccupy() { getCpuOccupyTime(m_currentTotalTime, m_currentUserTime); qDebug() << "current cpu time:" << m_currentTotalTime << m_currentUserTime; int cpuOccupy = (m_currentUserTime - m_lastUserTime) * 100/(m_currentTotalTime - m_lastTotalTime); qDebug() << "cpu occupy:" << cpuOccupy; m_lastTotalTime = m_currentTotalTime; m_lastUserTime = m_currentUserTime; if (cpuOccupy < m_offlineCpuOccupy) { emit cpuCoreSwitchSignal(false); } else if (cpuOccupy > m_onlineCpuOccupy){ emit cpuCoreSwitchSignal(true); } else { ; } } void UpmCpuOccupy::getCpuOccupyTime(quint64 &totalTime, quint64 &userTime) { QString result; quint64 total = 0; QStringList cpuState; if (true == UpmCommonFile::read(CPU_PROC_PATH, CPU_PROC_STATE, result)) { if (result.contains("cpu")) { cpuState = result.split(" "); // qDebug() << "cpu time list:" << cpuState; for (int i = 2; i < cpuState.size(); ++i) { total += cpuState[i].toULong(); } } } totalTime = total; userTime = total - cpuState[5].toULong(); } ukui-power-manager/registeredQDbus/cpu-control/upmcpucoreinfo.h0000664000175000017500000000375115167661430024006 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPMCPUCOREINFO_H #define UPMCPUCOREINFO_H #include #define CPU_DEVICES_PATH "/sys/devices/system/cpu/cpu%1/" #define CPU_CORE_ONLINE "online" #define CPU_DEVICES_FREQ_PATH "/sys/devices/system/cpu/cpu%1/cpufreq/" #define CPU_SCALING_GOVERNORS "scaling_governor" #define CPU_SCALING_AVAILABLE_GOVERNORS "scaling_available_governors" #define CPU_SCALING_MAX_FREQ "scaling_max_freq" #define CPU_SCALING_MIN_FREQ "scaling_min_freq" enum cpu_core_online_state { cpu_core_offline = 0, cpu_core_online, cpu_core_error, }; enum policy { Performance = 0, Balance, Powersave, max_policy }; class UpmCpuCoreInfo : public QObject { Q_OBJECT public: explicit UpmCpuCoreInfo(int cpuCoreId, QObject *parent = nullptr); int getCpuCoreOnlineState(void); void setCpuCoreOnlineState(int online); void setCorePolicy(int cpuPolicy); void setCoreMaxFreq(int cpuFrequency); int getDefaultCoreMaxFreq(); void setDefaultCoreMaxFreq(); QString getCpuCorePolicy(); private: int m_cpuCoreId = -1; int m_defaultMaxFreq = 0; int m_defaultMinFreq = 0; QStringList m_coreFreqMode = {"performance", "powersave", "powersave"}; signals: }; #endif // UPMCPUINFO_H ukui-power-manager/registeredQDbus/cpu-control/upmcpucontrol.cpp0000664000175000017500000002430615167661430024214 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upmcpucontrol.h" #include #include UpmCpuControl::UpmCpuControl(QObject *parent) : QObject(parent) { m_cpuCoreNum = QThread::idealThreadCount(); qDebug() << "m_cpuCoreNum :" << m_cpuCoreNum; m_maxCpuOnlineCore = m_cpuCoreNum - 1; m_cpuOnlineCore = m_maxCpuOnlineCore; for (int cpuCoreNum = 0; cpuCoreNum < m_cpuCoreNum; ++cpuCoreNum) { m_allCpuCoreInfo.push_back(new UpmCpuCoreInfo(cpuCoreNum, this)); } initSystemIdleReserveCpu0(); initBalanceModeLimitCpuFreq(); initAutoSwitchCpuCore(); } void UpmCpuControl::initSystemIdleReserveCpu0() { m_idleReserveCpu0[Performance] = false; m_idleReserveCpu0[Balance] = false; m_idleReserveCpu0[Powersave] = false; QStringList configKeys = {UPM_KEY_EXTEND_PERFORMANCE_IDEL_RESERVE_CPU0, UPM_KEY_EXTEND_BALANCE_IDEL_RESERVE_CPU0, UPM_KEY_EXTEND_POWERSAVE_IDEL_RESERVE_CPU0}; QString config; for (int policy = Performance; policy < max_policy; ++policy) { if (true == UpmCustomHardwareConfig::self()->getExtendConfig(configKeys[policy], config)) { if (1 == config.toInt()) { m_idleReserveCpu0[policy] = true; } } } } void UpmCpuControl::initBalanceModeLimitCpuFreq() { QString config; if (true == UpmCustomHardwareConfig::self()->getExtendConfig( UPM_KEY_EXTEND_BALANCE_MODE_REDUCE_FREQUENCY, config)) { if (1 == config.toInt()) { m_balanceModeSetMaxFreq = true; } } if (true == UpmCustomHardwareConfig::self()->getExtendConfig( UPM_KEY_EXTEND_BALANCE_MODE_MAX_FREQUENCY, config)) { m_balanceMaxCpuFrequency = config.toInt(); } } void UpmCpuControl::initAutoSwitchCpuCore() { m_cpuOccupy = new UpmCpuOccupy(this); connect(m_cpuOccupy, &UpmCpuOccupy::cpuCoreSwitchSignal, this, &UpmCpuControl::dealCpuSwitchSignal); for (int policy = Performance; policy < max_policy; ++policy) { initAutoSwitchCpuCoreConfig(policy); } } void UpmCpuControl::initAutoSwitchCpuCoreConfig(int cpuPolicy) { if (cpuPolicy < Performance || cpuPolicy > Powersave) { return ; } QStringList configKeys = {UPM_KEY_EXTEND_PERFORMANCE_AUTO_SWITCH_CPU_CORE, UPM_KEY_EXTEND_BALANCE_AUTO_SWITCH_CPU_CORE, UPM_KEY_EXTEND_POWERSAVE_AUTO_SWITCH_CPU_CORE}; m_configs[cpuPolicy].configActive = false; m_configs[cpuPolicy].cpuSamplingInterval = 30000; m_configs[cpuPolicy].offlineCpuOccupy = 50; m_configs[cpuPolicy].onlineCpuOccupy = 70; m_configs[cpuPolicy].reserveCoreNum = m_cpuCoreNum / 2; QString config; m_configs[cpuPolicy].configActive = UpmCustomHardwareConfig::self()->getExtendConfig(configKeys[cpuPolicy], config); if (true == m_configs[cpuPolicy].configActive) { QStringList configs = config.split("-"); if (max_auto_switch_cpu_core_config == configs.size()) { m_configs[cpuPolicy].cpuSamplingInterval = configs[cpu_sampling_interval].toInt(); m_configs[cpuPolicy].offlineCpuOccupy = configs[offline_cpu_occupy].toInt(); m_configs[cpuPolicy].onlineCpuOccupy = configs[online_cpu_occupy].toInt(); m_configs[cpuPolicy].reserveCoreNum = configs[reserve_core_num].toInt(); if (0 == m_configs[cpuPolicy].reserveCoreNum) { m_configs[cpuPolicy].reserveCoreNum = 1; } } else { m_configs[cpuPolicy].configActive = false; } } } int UpmCpuControl::getCpuCoreNum() { return m_cpuCoreNum; } void UpmCpuControl::setCorePolicy(int cpuCoreId, int cpuPolicy) { if (cpuCoreId >= m_cpuCoreNum) { return ; } m_allCpuCoreInfo[cpuCoreId]->setCorePolicy(cpuPolicy); } QString UpmCpuControl::getCpuCorePolicy(int cpuCoreId) { if (cpuCoreId >= m_cpuCoreNum) { return "cpu core id failed"; } return m_allCpuCoreInfo[cpuCoreId]->getCpuCorePolicy(); } void UpmCpuControl::setCoreMaxFreq(int cpuCoreId, int cpuFrequency) { if (cpuCoreId >= m_cpuCoreNum) { return ; } m_allCpuCoreInfo[cpuCoreId]->setCoreMaxFreq(cpuFrequency); } int UpmCpuControl::getDefaultCoreMaxFreq(int cpuCoreId) { return m_allCpuCoreInfo[cpuCoreId]->getDefaultCoreMaxFreq(); } void UpmCpuControl::setCoreDefaultMaxFreq(int cpuCoreId) { if (cpuCoreId >= m_cpuCoreNum) { return ; } m_allCpuCoreInfo[cpuCoreId]->setDefaultCoreMaxFreq(); } void UpmCpuControl::setAllCorePolicy(int cpuPolicy) { if (cpuPolicy < Performance || cpuPolicy > Powersave) { return ; } m_cpuPolicy = cpuPolicy; m_cpuOccupy->stopCalcCpuOccupy(); for (int cpuCoreNum = 0; cpuCoreNum < m_cpuCoreNum; ++cpuCoreNum) { setCpuCoreOnlineState(cpuCoreNum, cpu_core_online); if (true == m_balanceModeSetMaxFreq) { if (Balance == m_cpuPolicy) { if (0 == m_balanceMaxCpuFrequency) { setCoreMaxFreq(cpuCoreNum, getDefaultCoreMaxFreq(cpuCoreNum) * 0.8); } else { setCoreMaxFreq(cpuCoreNum, m_balanceMaxCpuFrequency); } } else { setCoreDefaultMaxFreq(cpuCoreNum); } } m_allCpuCoreInfo[cpuCoreNum]->setCorePolicy(m_cpuPolicy); } m_cpuOnlineCore = m_maxCpuOnlineCore; if (true == m_configs[m_cpuPolicy].configActive) { m_cpuOccupy->startCalcCpuOccupy(m_configs[m_cpuPolicy].cpuSamplingInterval, m_configs[m_cpuPolicy].offlineCpuOccupy, m_configs[m_cpuPolicy].onlineCpuOccupy); } } void UpmCpuControl::setAllCoreMaxFreq(int cpuFrequency) { for (int cpuCoreNum = 0; cpuCoreNum < m_cpuCoreNum; ++cpuCoreNum) { m_allCpuCoreInfo[cpuCoreNum]->setCoreMaxFreq(cpuFrequency); } } void UpmCpuControl::setAllCoreDefaultMaxFreq() { for (int cpuCoreNum = 0; cpuCoreNum < m_cpuCoreNum; ++cpuCoreNum) { m_allCpuCoreInfo[cpuCoreNum]->setDefaultCoreMaxFreq(); } } int UpmCpuControl::getCpuCoreOnlineState(int cpuCoreId) { if (cpuCoreId >= m_cpuCoreNum) { return cpu_core_error; } return m_allCpuCoreInfo[cpuCoreId]->getCpuCoreOnlineState(); } void UpmCpuControl::setCpuCoreOnlineState(int cpuCoreId, int online) { if (cpuCoreId >= m_cpuCoreNum) { return ; } if (0 == cpuCoreId) { return ; } m_allCpuCoreInfo[cpuCoreId]->setCpuCoreOnlineState(online); } void UpmCpuControl::systemIdleReserveCpu0(bool systmIdle) { qDebug() << "systemIdleReserveCpu0 :" << systmIdle; if (true == systmIdle) { //系统进入空闲,不在通过计算cpu占用率控制开关核心,停止用于计算cpu占用率的定时器 m_cpuOccupy->stopCalcCpuOccupy(); qDebug() << "m_cpuPolicy :" << m_cpuPolicy << "idleReserveCpu0 :" << m_idleReserveCpu0[m_cpuPolicy]; if (true == m_idleReserveCpu0[m_cpuPolicy]) { qDebug() << "1 m_cpuOnlineCore :" << m_cpuOnlineCore; //空闲时,仅保留一个cpu核心的功能enable,关闭其他核心 while (m_cpuOnlineCore > 0) { qDebug() << "cpu core offline :" << m_cpuOnlineCore; setCpuCoreOnlineState(m_cpuOnlineCore, cpu_core_offline); m_cpuOnlineCore--; } } else { qDebug() << "2 m_cpuOnlineCore :" << m_cpuOnlineCore; //空闲时,仅保留一个cpu核心的功能disable,开启以关闭的核心 while (m_cpuOnlineCore < m_maxCpuOnlineCore) { m_cpuOnlineCore++; qDebug() << "cpu core online :" << m_cpuOnlineCore; setCpuCoreOnlineState(m_cpuOnlineCore, cpu_core_online); } } } else { //非空闲状态,开启所有的cpu核心 qDebug() << "3 m_cpuOnlineCore :" << m_cpuOnlineCore; while (m_cpuOnlineCore < m_maxCpuOnlineCore) { m_cpuOnlineCore++; qDebug() << "cpu core online :" << m_cpuOnlineCore; setCpuCoreOnlineState(m_cpuOnlineCore, cpu_core_online); } if (true == m_configs[m_cpuPolicy].configActive) { qDebug() << "cpu policy :" << m_cpuPolicy << "start calc cpu occupy"; //非空闲状态,动态开关核心功能enable,重新打开计算cpu占用率的定时器 m_cpuOccupy->startCalcCpuOccupy(m_configs[m_cpuPolicy].cpuSamplingInterval, m_configs[m_cpuPolicy].offlineCpuOccupy, m_configs[m_cpuPolicy].onlineCpuOccupy); } } } void UpmCpuControl::enableBalanceModeFrequency(bool enable) { m_balanceModeSetMaxFreq = enable; } void UpmCpuControl::enableSystemIdleReserveCpu0(bool enable, int cpuPolicy) { m_idleReserveCpu0[cpuPolicy] = enable; } void UpmCpuControl::enableAutoSwitchCpuCore(bool enable, int cpuPolicy) { if (cpuPolicy < Performance || cpuPolicy > Powersave) { return ; } m_configs[cpuPolicy].configActive = enable; } void UpmCpuControl::dealCpuSwitchSignal(bool coreOnline) { if (true == coreOnline) { if (m_cpuOnlineCore < m_maxCpuOnlineCore) { m_cpuOnlineCore++; setCpuCoreOnlineState(m_cpuOnlineCore, cpu_core_online); } } else { if (m_cpuOnlineCore >= m_configs[m_cpuPolicy].reserveCoreNum) { setCpuCoreOnlineState(m_cpuOnlineCore, cpu_core_offline); m_cpuOnlineCore--; } } } ukui-power-manager/registeredQDbus/cpu-control/upmcpucoreinfo.cpp0000664000175000017500000000717215167661430024342 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upmcpucoreinfo.h" #include "../upmcommonfile.h" UpmCpuCoreInfo::UpmCpuCoreInfo(int cpuCoreId, QObject *parent) : QObject(parent) { m_cpuCoreId = cpuCoreId; QString result; if (true == UpmCommonFile::read(QString(CPU_DEVICES_FREQ_PATH).arg(m_cpuCoreId), CPU_SCALING_AVAILABLE_GOVERNORS, result)) { if (result.contains("ondemand")) { m_coreFreqMode[Balance] = "ondemand"; } else if (result.contains("schedutil")) { m_coreFreqMode[Balance] = "schedutil"; } } if (true == UpmCommonFile::read(QString(CPU_DEVICES_FREQ_PATH).arg(m_cpuCoreId), CPU_SCALING_MAX_FREQ, result)) { m_defaultMaxFreq = result.toUInt(); } if (true == UpmCommonFile::read(QString(CPU_DEVICES_FREQ_PATH).arg(m_cpuCoreId), CPU_SCALING_MIN_FREQ, result)) { m_defaultMinFreq = result.toUInt(); } } int UpmCpuCoreInfo::getCpuCoreOnlineState() { QString result; if (true == UpmCommonFile::read(QString(CPU_DEVICES_PATH).arg(m_cpuCoreId), CPU_CORE_ONLINE, result)) { return result.toInt(); } return cpu_core_error; } void UpmCpuCoreInfo::setCpuCoreOnlineState(int online) { if (cpu_core_online == online || cpu_core_offline == online) { UpmCommonFile::write(QString(CPU_DEVICES_PATH).arg(m_cpuCoreId), CPU_CORE_ONLINE, QString::number(online)); } } void UpmCpuCoreInfo::setCorePolicy(int cpuPolicy) { if (cpuPolicy < Performance || cpuPolicy > Powersave) { return ; } UpmCommonFile::write(QString(CPU_DEVICES_FREQ_PATH).arg(m_cpuCoreId), CPU_SCALING_GOVERNORS, m_coreFreqMode[cpuPolicy]); } void UpmCpuCoreInfo::setCoreMaxFreq(int cpuFrequency) { if (cpuFrequency > m_defaultMaxFreq) { UpmCommonFile::write(QString(CPU_DEVICES_FREQ_PATH).arg(m_cpuCoreId), CPU_SCALING_MAX_FREQ, QString::number(m_defaultMaxFreq)); } else if (cpuFrequency < m_defaultMinFreq) { UpmCommonFile::write(QString(CPU_DEVICES_FREQ_PATH).arg(m_cpuCoreId), CPU_SCALING_MAX_FREQ, QString::number(m_defaultMinFreq)); } else { UpmCommonFile::write(QString(CPU_DEVICES_FREQ_PATH).arg(m_cpuCoreId), CPU_SCALING_MAX_FREQ, QString::number(cpuFrequency)); } } int UpmCpuCoreInfo::getDefaultCoreMaxFreq() { return m_defaultMaxFreq; } void UpmCpuCoreInfo::setDefaultCoreMaxFreq() { UpmCommonFile::write(QString(CPU_DEVICES_FREQ_PATH).arg(m_cpuCoreId), CPU_SCALING_MAX_FREQ, QString::number(m_defaultMaxFreq)); } QString UpmCpuCoreInfo::getCpuCorePolicy() { QString result; UpmCommonFile::read(QString(CPU_DEVICES_FREQ_PATH).arg(m_cpuCoreId), CPU_SCALING_GOVERNORS, result); return result; } ukui-power-manager/registeredQDbus/cpu-control/upmcpucontrol.h0000664000175000017500000000524515167661430023662 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPMCPUCONTROL_H #define UPMCPUCONTROL_H #include #include #include "upmcpucoreinfo.h" #include "upmcpuoccupy.h" #include "../upmcustomhardwareconfig.h" enum em_auto_switch_cpu_core_config { cpu_sampling_interval = 0, offline_cpu_occupy, online_cpu_occupy, reserve_core_num, max_auto_switch_cpu_core_config }; typedef struct stu_auto_switch_cpu_core_config { int cpuSamplingInterval; int offlineCpuOccupy; int onlineCpuOccupy; int reserveCoreNum; bool configActive; }AutoSwitchCpuCoreConfig; class UpmCpuControl : public QObject { Q_OBJECT public: explicit UpmCpuControl(QObject *parent = nullptr); int getCpuCoreNum(); void setCorePolicy(int cpuCoreId, int cpuPolicy); QString getCpuCorePolicy(int cpuCoreId); void setCoreMaxFreq(int cpuCoreId, int cpuFrequency); int getDefaultCoreMaxFreq(int cpuCoreId); void setCoreDefaultMaxFreq(int cpuCoreId); void setAllCorePolicy(int cpuPolicy); void setAllCoreMaxFreq(int cpuFrequency); void setAllCoreDefaultMaxFreq(); int getCpuCoreOnlineState(int cpuCoreId); void setCpuCoreOnlineState(int cpuCoreId, int online); void systemIdleReserveCpu0(bool systmIdle); void enableBalanceModeFrequency(bool enable); void enableSystemIdleReserveCpu0(bool enable, int cpuPolicy); void enableAutoSwitchCpuCore(bool enable, int cpuPolicy); private: int m_cpuCoreNum; int m_cpuPolicy; QVector m_allCpuCoreInfo; int m_balanceMaxCpuFrequency = 0; bool m_balanceModeSetMaxFreq = false; bool m_idleReserveCpu0[max_policy]; UpmCpuOccupy *m_cpuOccupy; AutoSwitchCpuCoreConfig m_configs[max_policy]; int m_maxCpuOnlineCore; int m_cpuOnlineCore; void initSystemIdleReserveCpu0(); void initBalanceModeLimitCpuFreq(); void initAutoSwitchCpuCore(); void initAutoSwitchCpuCoreConfig(int cpuPolicy); private slots: void dealCpuSwitchSignal(bool); signals: }; #endif // UPMCPUCONTROL_H ukui-power-manager/registeredQDbus/powerconfig.cpp0000664000175000017500000000346015167661430021355 0ustar fengfeng/* * Copyright (C) 2024, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "powerconfig.h" #include PowerConfig::PowerConfig(QObject *parent) : QObject(parent) { m_qsettings = new QSettings(POWER_MANAGER_CONF_PATH, QSettings::NativeFormat); QVariant value; if (true == getPowerConfig(POWER_MANAGER_RUN_TIMES, value)) { m_powerManagerRunTimes = value.toInt(); } m_powerManagerRunTimes++; updatePowerConfig(POWER_MANAGER_RUN_TIMES, QString::number(m_powerManagerRunTimes)); } PowerConfig::~PowerConfig() {} int PowerConfig::getPowerManagerRunTimes() { return m_powerManagerRunTimes; } void PowerConfig::updatePowerConfig(const QString &key, const QString &value) { m_qsettings->sync(); m_qsettings->beginGroup(CONFIG_GROUP_CONFIG); m_qsettings->setValue(key, value); m_qsettings->endGroup(); m_qsettings->sync(); } bool PowerConfig::getPowerConfig(const QString &key, QVariant &value) { m_qsettings->beginGroup(CONFIG_GROUP_CONFIG); value = m_qsettings->value(key, POWER_MANAGER_NO_THIS_KEY); m_qsettings->endGroup(); if (POWER_MANAGER_NO_THIS_KEY == value.toString()) { return false; } return true; } ukui-power-manager/registeredQDbus/upmcustomhardwareconfig.cpp0000664000175000017500000001642515167661430024000 0ustar fengfeng/* * Copyright 2024 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upmcustomhardwareconfig.h" #include #include #include Q_GLOBAL_STATIC(UpmCustomHardwareConfig, s_upmCustomHardwareConfig) UpmCustomHardwareConfig::UpmCustomHardwareConfig(QObject *parent) : QObject(parent) { getHardwareInfo(); getCpuType(); m_globalConfig = new QSettings(UPM_GLOBAL_HARDWARE_CONFIG_FILE, QSettings::IniFormat, this); m_globalConfig->beginGroup(UPM_GROUP_THIS_PRODUCT); //是否是首次运行 if (1 == m_globalConfig->value(UPM_KEY_FIRST_RUN).toInt()) { //是否有扩展配置,对应品牌 if (true == getExtendConfigFile(m_extendConfigPath)) { //有扩展配置,将配置文件路径写入全局配置文件 m_globalConfig->setValue(UPM_KEY_EXTEND_CONFIG_PATH, m_extendConfigPath); m_extendConfig = new QSettings(m_extendConfigPath, QSettings::IniFormat, this); m_extendConfig->beginGroup("product"); //配置文件中group[product]为产品标识,标识与硬件信息对应做为group,标识下的key为配置内容 QStringList productList = m_extendConfig->allKeys(); Q_FOREACH (const QString &product, productList) { if (m_hardwareInfo.contains(product, Qt::CaseInsensitive)) { //扩展配置中,有对应产品型号,将标识写入全局配置 if (1 == m_extendConfig->value(product).toInt()) { m_productGroup = product; m_globalConfig->setValue(UPM_KEY_DEVICE_IDENTIFICATION, m_productGroup); } break; } } m_extendConfig->endGroup(); } m_globalConfig->setValue(UPM_KEY_FIRST_RUN, 0); } else { //不是首次运行,直接从全局配置中读取配置文件及产品标识 m_extendConfigPath = m_globalConfig->value(UPM_KEY_EXTEND_CONFIG_PATH).toString(); m_productGroup = m_globalConfig->value(UPM_KEY_DEVICE_IDENTIFICATION).toString(); if (false == m_extendConfigPath.isEmpty()) { qDebug() << "extend config path:" << m_extendConfigPath; m_extendConfig = new QSettings(m_extendConfigPath, QSettings::IniFormat, this); } } m_globalConfig->endGroup(); m_globalConfig->sync(); } UpmCustomHardwareConfig::~UpmCustomHardwareConfig() {} UpmCustomHardwareConfig *UpmCustomHardwareConfig::self() { return s_upmCustomHardwareConfig; } bool UpmCustomHardwareConfig::isPanguM900() { if (true == m_cpuType.contains("PANGU M900", Qt::CaseInsensitive)) { return true; } return false; } bool UpmCustomHardwareConfig::isHygonCpu() { if (true == m_cpuType.contains("Hygon", Qt::CaseInsensitive)) { return true; } return false; } bool UpmCustomHardwareConfig::brightnessNodeEffective() { QVariant value; if (true == readConfig(m_globalConfig, UPM_GROUP_IGNORE_BRIGHTNESS_NODE, UPM_KEY_BOARD_NAME, value)) { QStringList boards = value.toString().split(","); Q_FOREACH (const QString &board, boards) { if (m_hardwareInfo.contains(board, Qt::CaseInsensitive) && !board.isEmpty()) { return false; } } } return true; } QString UpmCustomHardwareConfig::getBrightnessNode() { if (nullptr != m_extendConfig) { QVariant value; if (true == readConfig(m_extendConfig, m_productGroup, UPM_KEY_EXTEND_BRIGHTNESS_NODE, value)) { return value.toString(); } } QStringList cpuAndNodes = {"ZHAOXIN:acpi_video0", "loongson:loongson-gpu", "Phytium:ec_bl"}; Q_FOREACH (const QString &str, cpuAndNodes) { QStringList cpuAndNode = str.split(":"); if (m_cpuType.contains(cpuAndNode[0], Qt::CaseInsensitive)) { return cpuAndNode[1]; } } return QString(); } bool UpmCustomHardwareConfig::firstRunDonotSuspend() { if (nullptr != m_extendConfig) { QVariant value; if (true == readConfig(m_extendConfig, UPM_GROUP_EXTEND_BRAND_GENERIC_CONFIG, UPM_KEY_FIRST_RUN_DONOT_SUSPEND, value)) { if (1 == value.toInt()) { return true; } } } return false; } bool UpmCustomHardwareConfig::getExtendConfig(const QString &configKey, QString &config) { QVariant value; if (true == readConfig(m_extendConfig, m_productGroup, configKey, value)) { config = value.toString(); return true; } return false; } void UpmCustomHardwareConfig::getHardwareInfo() { if (false == readAll(UPM_HARDWARE_INFO_FILE, m_hardwareInfo)) { qDebug() << "get hardware info failed"; } } void UpmCustomHardwareConfig::getCpuType() { if (false == readAll(UPM_CPU_INFO_FILE, m_cpuType)) { qDebug() << "get cpu info failed"; } } bool UpmCustomHardwareConfig::readConfig(QSettings *settings, const QString &group, const QString &key, QVariant &value) { if (nullptr == settings) { return false; } settings->beginGroup(group); value = settings->value(key, UPM_NO_THIS_KEY); settings->endGroup(); if (UPM_NO_THIS_KEY == value.toString()) { return false; } return true; } bool UpmCustomHardwareConfig::getExtendConfigFile(QString &configFilePath) { QDir extendConfigDir(UPM_EXTEND_HARDWARE_CONFIG_PATH); if (true == extendConfigDir.exists()) { QStringList extendConfigs = extendConfigDir.entryList(QDir::Files | QDir::NoDotAndDotDot); qDebug() << "dirs :" << extendConfigDir; Q_FOREACH (const QString &extendConfig, extendConfigs) { qDebug() << "extend config:" << extendConfig; QStringList fileName = extendConfig.split("."); qDebug() << "fileName:" << fileName; if (m_hardwareInfo.contains(fileName[0], Qt::CaseInsensitive)) { configFilePath = QString(UPM_EXTEND_HARDWARE_CONFIG_PATH) + extendConfig; qDebug() << "configFilePath:" << configFilePath; return true; } } } qDebug() << "get extend config file failed"; return false; } bool UpmCustomHardwareConfig::readAll(const QString &filePath, QString &content) { QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "read file error :" << filePath; return false; } content = file.readAll(); file.close(); return true; } ukui-power-manager/registeredQDbus/main.cpp0000664000175000017500000000331115167661430017752 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "sysdbusregister.h" #include "syslog-handler.hpp" // 初始化静态成员变量 QMutex SyslogHandler::mutex; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); app.setOrganizationName("Kylin Team"); app.setApplicationName("ukui-powermanagement-service"); // 安装消息处理程序 qInstallMessageHandler(SyslogHandler::staticMessageHandler); QDBusConnection systemBus = QDBusConnection::systemBus(); if (!systemBus.registerService("org.ukui.powermanagement")) { qCritical() << "QDbus register service failed reason:" << systemBus.lastError(); exit(0); } if (!systemBus.registerObject( "/", new SysdbusRegister(), QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals)) { qCritical() << "QDbus register object failed reason:" << systemBus.lastError(); exit(0); } return app.exec(); } ukui-power-manager/registeredQDbus/sysdbusregister.h0000664000175000017500000001240115167661430021734 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SYSDBUSREGISTER_H #define SYSDBUSREGISTER_H #include #include #define TLP_ORIGIN_CONF "/usr/share/ukui-power-manager/tlp/origin.conf" #define TLP_ORIGIN_DEFAULT_CONFIG "/usr/share/ukui-power-manager/tlp/upm_origin.conf" #define TLP_ORIGIN_GET_PATH_SH "/usr/share/ukui-power-manager/tlp/get_tlp_bat_paths.sh" #define TLP_SET_WHITE_LIST "kysec_set -n exectl -v verified /usr/share/ukui-power-manager/tlp/tlp" #define TLP_SET_WHITE_LIST1 "kysec_set -n exectl -v verified /usr/share/ukui-power-manager/tlp/func.d/05-tlp-func-pm" #define TLP_SET_WHITE_LIST2 "kysec_set -n exectl -v verified /usr/share/ukui-power-manager/tlp/func.d/10-tlp-func-cpu" #define TLP_SET_WHITE_LIST3 "kysec_set -n exectl -v verified /usr/share/ukui-power-manager/tlp/func.d/15-tlp-func-disk" #define TLP_SET_WHITE_LIST4 "kysec_set -n exectl -v verified /usr/share/ukui-power-manager/tlp/func.d/20-tlp-func-usb" #define TLP_SET_WHITE_LIST5 "kysec_set -n exectl -v verified /usr/share/ukui-power-manager/tlp/func.d/25-tlp-func-rf" #define TLP_SET_WHITE_LIST6 "kysec_set -n exectl -v verified /usr/share/ukui-power-manager/tlp/func.d/30-tlp-func-rf-sw" #define TLP_SET_WHITE_LIST7 "kysec_set -n exectl -v verified /usr/share/ukui-power-manager/tlp/func.d/35-tlp-func-batt" #define TLP_SET_WHITE_LIST8 "kysec_set -n exectl -v verified /usr/share/ukui-power-manager/tlp/func.d/40-tlp-func-bay" #define TLP_SET_WHITE_LIST9 "kysec_set -n exectl -v verified /usr/share/ukui-power-manager/tlp/func.d/45-tlp-func-gpu" #define TLP_SET_WHITE_LIST10 "kysec_set -n exectl -v verified /usr/share/ukui-power-manager/tlp/func.d/tlp-func-stat" #include "dev-power-control/devpowercontrol.h" #include "brightness-control/brightnessnode.h" #include "cpu-control/upmcpucontrol.h" #include "hardware-power-control/hardwarepowercontrol.h" #include "upmcustomhardwareconfig.h" #include "hardware-reader/hardwarereader.h" #define TLP_BAT_CMD "/usr/share/ukui-power-manager/tlp/tlp bat" #include "powerconfig.h" #include "upmcustomhardwareconfig.h" #include class SysdbusRegister : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.ukui.powermanagement.interface") public: explicit SysdbusRegister(); ~SysdbusRegister(); private: /** * @brief controlLogin1Connection * 创建与login1的dbus连接 */ void controlLogin1Connection(QString ); QString canControl(const QString ); PowerConfig *m_powerConfig; BrightnessNode *m_brightnessNode; qint64 m_currentBrightness = -1; UpmCpuControl *m_upmCpuControl; bool m_isPanguM900 = false; int m_cpuPolicy; DevPowerControl *m_devPowerControl; HardwarePowerControl *m_hardwarePowerControl; QProcess *m_progress; QMap m_tlpMap; bool checkEnviron(int pid); /** 检查tlp默认配置是否存在 * @brief checkTlpOrigin */ void checkTlpOrigin(); /** 读取所有的默认节点写入到配置文件内。 * @brief genDefaultConfig */ bool genDefaultConfig(); /** 读取缺省值到map内。 * @brief readAllNodeToMap */ bool readAllNodeToMap(); public slots: Q_SCRIPTABLE bool CanSetBrightness(); Q_SCRIPTABLE QString RegulateBrightness(qulonglong); Q_SCRIPTABLE QString resetBrightness(); Q_SCRIPTABLE void CpuFreqencyModulation(int); Q_SCRIPTABLE void GpuFreqencyModulation(const int); Q_SCRIPTABLE qulonglong GetMaxBrightness(); Q_SCRIPTABLE qulonglong GetBrightness(); /** * @brief IsBrightnessEnhancement‌ * 是否支持亮度增强 * false 不支持(默认);true 支持 * @return */ Q_SCRIPTABLE bool IsBrightnessEnhancementSupported(); Q_SCRIPTABLE void SetAudioMode(const int); Q_SCRIPTABLE void SetPcieAspmMode(const int); Q_SCRIPTABLE int GetCpuPolicy(); Q_SCRIPTABLE void SystemIdleReserveCpu0(bool); Q_SCRIPTABLE void EnableReduceCpuFrequency(bool); Q_SCRIPTABLE void EnableSystemIdleReserveCpu0(bool, int); Q_SCRIPTABLE void EnableAutoSwitchCpuCore(bool, int); Q_SCRIPTABLE void enterTlp(); Q_SCRIPTABLE void exitTlp(); Q_SCRIPTABLE QString printfTlpNodeValue(); Q_SCRIPTABLE int GetCpuCoreNum(); Q_SCRIPTABLE QString GetCpuCorePolicy(int); Q_SCRIPTABLE bool FirstRunDonotSuspend(); Q_SCRIPTABLE bool isFlemingXModel(); private: Q_PROPERTY(bool IsBrightnessEnhancementSupported READ IsBrightnessEnhancementSupported) }; #endif // SYSDBUSREGISTER_H ukui-power-manager/registeredQDbus/sysdbusregister.cpp0000664000175000017500000002242615167661430022277 0ustar fengfeng/* * Copyright 2021 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "sysdbusregister.h" #include SysdbusRegister::SysdbusRegister() { m_powerConfig = new PowerConfig(this); m_brightnessNode = new BrightnessNode(this); checkTlpOrigin(); m_upmCpuControl = new UpmCpuControl(this); m_devPowerControl = new DevPowerControl(this); m_hardwarePowerControl = new HardwarePowerControl(this); } SysdbusRegister::~SysdbusRegister() {} bool SysdbusRegister::CanSetBrightness() { return m_brightnessNode->canSetBrightness(); } bool SysdbusRegister::checkEnviron(int pid) { QString filePath = QString("/proc/%1/environ").arg(pid); QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "file.open failed" << filePath; return false; } QTextStream in(&file); QString data = in.readAll(); file.close(); data.replace('\0', '\n'); QStringList environVars = data.split('\n'); for (const QString &var : environVars) { if (!var.isEmpty()) { int pos = var.indexOf('='); if (pos != -1) { QString key = var.left(pos); if (key == "LD_PRELOAD" || key == "LD_LIBRARY_PATH" || key == "LD_AUDIT") { return false; } } } } return true; } qulonglong SysdbusRegister::GetMaxBrightness() { if (false == m_brightnessNode->canSetBrightness()) { return 0; } return m_brightnessNode->getMaxBrightness(); } qulonglong SysdbusRegister::GetBrightness() { if (false == m_brightnessNode->canSetBrightness()) { return 0; } return m_brightnessNode->getCurrentBrightness(); } QString SysdbusRegister::RegulateBrightness(qulonglong brightness) { if (false == m_brightnessNode->canSetBrightness()) { return "no effective node"; } m_currentBrightness = brightness; return m_brightnessNode->setCurrentBrightness(brightness); } QString SysdbusRegister::resetBrightness() { if (m_currentBrightness < 0){ return "unset"; } if (false == m_brightnessNode->canSetBrightness()) { return "no effective node"; } return m_brightnessNode->setCurrentBrightness(m_currentBrightness); } bool SysdbusRegister::IsBrightnessEnhancementSupported() { return m_brightnessNode->isBrightnessEnhancementSupported(); } void SysdbusRegister::CpuFreqencyModulation(int strategy) { m_cpuPolicy = strategy; // 条件解释: // 1. 如果不是M900设备(false == isPanguM900()) -> 应用CPU控制 // 2. 如果是M900但也是PWC30设备(true == isPgwDevice()) -> 应用CPU控制 // 3. 只有在是M900且不是PWC30时 -> 跳过CPU控制 // 使用HardwareReader HardwareReader *reader = HardwareReader::instance(); if (false == reader->isPanguM900() || true == reader->isPgwDevice()) { m_upmCpuControl->setAllCorePolicy(strategy); } else { qInfo() << "Skipping CPU control: device is M900 but not PWC30"; } // 设备电源管理对所有设备类型都应用(保持不变) if (Performance == strategy) { m_devPowerControl->setAllDevicePerformance(); } else if (Powersave == strategy) { m_devPowerControl->setAllDeviceSave(); } else { m_devPowerControl->setAllDeviceBalance(); } } bool SysdbusRegister::FirstRunDonotSuspend() { if (1 == m_powerConfig->getPowerManagerRunTimes() && true == UpmCustomHardwareConfig::self()->firstRunDonotSuspend()) { return true; } return false; } void SysdbusRegister::GpuFreqencyModulation(int strategy) { m_hardwarePowerControl->setGpuFrequencyMode(strategy); } void SysdbusRegister::SetAudioMode(int strategy) { m_hardwarePowerControl->setAudioMode(strategy); } void SysdbusRegister::SetPcieAspmMode(int strategy) { m_hardwarePowerControl->setPcieAspmMode(strategy); } int SysdbusRegister::GetCpuPolicy() { return m_cpuPolicy; } void SysdbusRegister::SystemIdleReserveCpu0(bool systemIdle) { m_upmCpuControl->systemIdleReserveCpu0(systemIdle); } void SysdbusRegister::EnableReduceCpuFrequency(bool enable) { m_upmCpuControl->enableBalanceModeFrequency(enable); } void SysdbusRegister::EnableSystemIdleReserveCpu0(bool enable, int cpuPolicy) { m_upmCpuControl->enableSystemIdleReserveCpu0(enable, cpuPolicy); } void SysdbusRegister::EnableAutoSwitchCpuCore(bool enable, int cpuPolicy) { m_upmCpuControl->enableAutoSwitchCpuCore(enable, cpuPolicy); } void SysdbusRegister::enterTlp() { checkTlpOrigin(); QProcess::startDetached(TLP_BAT_CMD); } void SysdbusRegister::exitTlp() { checkTlpOrigin();//退出不用tlp ac是担心出现配置异常的问题。 for (auto it = m_tlpMap.begin(); it != m_tlpMap.end(); ++it) { QFile qfile(it.key()); if (!qfile.exists()) { continue; } // UPM_LOG(LOG_DEBUG,"write:%s=%s",it.key().toLatin1().data(), it.value().toLatin1().data()); qfile.open(QIODevice::WriteOnly|QIODevice::Text); qfile.write(it.value().toLatin1().data()); qfile.close(); } } QString SysdbusRegister::printfTlpNodeValue() { QFile tlpOrigin(TLP_ORIGIN_CONF); QString allnodes; QStringList nodeList; QString ret = ""; if (!tlpOrigin.exists()) { return ""; } tlpOrigin.open(QIODevice::ReadOnly|QIODevice::Text); allnodes = tlpOrigin.readAll(); nodeList = allnodes.split("\n"); Q_FOREACH (const QString str, nodeList) { QFile nodeFile(str); if (!nodeFile.exists()) { continue; } nodeFile.open(QIODevice::ReadOnly|QIODevice::Text); QString nodeValue = nodeFile.readAll(); nodeFile.close(); ret += str + "=" + nodeValue; // UPM_LOG(LOG_DEBUG,"write:%s=%s",str.toLatin1().data(), nodeValue.toLatin1().data()); } return ret; } void SysdbusRegister::checkTlpOrigin() { QFile tlpOrigin(TLP_ORIGIN_CONF); QFile tlpOriginConf(TLP_ORIGIN_DEFAULT_CONFIG); QString cmd = TLP_ORIGIN_GET_PATH_SH; if (tlpOriginConf.exists()) { readAllNodeToMap(); return; } if (tlpOrigin.exists()) { genDefaultConfig(); return; } //把可执行程序加入白名单,这样就不会有弹窗报警了。 QProcess::startDetached(TLP_SET_WHITE_LIST); QProcess::startDetached(TLP_SET_WHITE_LIST1); QProcess::startDetached(TLP_SET_WHITE_LIST2); QProcess::startDetached(TLP_SET_WHITE_LIST3); QProcess::startDetached(TLP_SET_WHITE_LIST4); QProcess::startDetached(TLP_SET_WHITE_LIST5); QProcess::startDetached(TLP_SET_WHITE_LIST6); QProcess::startDetached(TLP_SET_WHITE_LIST7); QProcess::startDetached(TLP_SET_WHITE_LIST8); QProcess::startDetached(TLP_SET_WHITE_LIST9); QProcess::startDetached(TLP_SET_WHITE_LIST10); m_progress = new QProcess(this); connect(m_progress, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(doProcessResult(int,QProcess::ExitStatus))); m_progress->startDetached(cmd); } bool SysdbusRegister::genDefaultConfig() { QFile tlpOrigin(TLP_ORIGIN_CONF); QString allnodes; QStringList nodeList; if (!tlpOrigin.exists()) { return false; } tlpOrigin.open(QIODevice::ReadOnly|QIODevice::Text); allnodes = tlpOrigin.readAll(); nodeList = allnodes.split("\n"); m_tlpMap.clear(); Q_FOREACH (const QString str, nodeList) { QFile nodeFile(str); if (!nodeFile.exists()) { continue; } nodeFile.open(QIODevice::ReadOnly|QIODevice::Text); QString nodeValue = nodeFile.readAll(); if (str.contains("energy_performance_preference") && nodeValue.contains("power")) { //error,异常数据不进行备份。 return false; } nodeFile.close(); m_tlpMap.insert(str, nodeValue.replace("\n","")); } tlpOrigin.close(); QSettings settings(TLP_ORIGIN_DEFAULT_CONFIG, QSettings::NativeFormat); for (auto it = m_tlpMap.begin(); it != m_tlpMap.end(); ++it) { settings.setValue(it.key(), it.value()); } return true; } bool SysdbusRegister::readAllNodeToMap() { QSettings settings(TLP_ORIGIN_DEFAULT_CONFIG, QSettings::IniFormat); QStringList keys = settings.allKeys(); m_tlpMap.clear(); for (const QString &key : keys) { m_tlpMap.insert("/"+key, settings.value(key).toString()); } return true; } int SysdbusRegister::GetCpuCoreNum() { return m_upmCpuControl->getCpuCoreNum(); } QString SysdbusRegister::GetCpuCorePolicy(int cpuCoreId) { return m_upmCpuControl->getCpuCorePolicy(cpuCoreId); } bool SysdbusRegister::isFlemingXModel() { HardwareReader reader; return reader.isFlemingX(); }ukui-power-manager/registeredQDbus/hardware-reader/0000775000175000017500000000000015167661430021361 5ustar fengfengukui-power-manager/registeredQDbus/hardware-reader/hardwarereader.h0000664000175000017500000002176315167661430024523 0ustar fengfeng/* * Copyright 2025 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef HARDWAREREADER_H #define HARDWAREREADER_H #include #include #include #include #define UPM_CPU_INFO_FILE QStringLiteral("/proc/cpuinfo") const QString DMI_PATH = "/sys/class/dmi/id/"; const QString DRM_PATH = "/sys/class/drm/"; class HardwareReader { public: HardwareReader(); ~HardwareReader(); static HardwareReader* instance(); bool isPanguM900() const; bool isPgwDevice() const; bool isFlemingX(); /** * @brief getDMIInfo * @param field 字段 * bios_date board_vendor chassis_version product_sku bios_vendor board_version modalias product_uuid bios_version chassis_asset_tag power product_version board_asset_tag chassis_serial product_family subsystem board_name chassis_type product_name sys_vendor board_serial chassis_vendor product_serial uevent * @return */ QString getDMIInfo(const QString field) const; private: QString executeCommand(const QString &command) const; QString getSystemProductName(); bool readFile(const QString &filePath, QString &content); void getCpuType(); static HardwareReader* m_instance; QString m_cpuType; }; class EdidComparator { public: // 读取当前连接的EDID static QMap readCurrentEdids() { QMap edidMap; QDir drmDir("/sys/class/drm"); foreach (const QString &card, drmDir.entryList({"card*"}, QDir::Dirs)) { QDir cardDir(drmDir.filePath(card)); foreach (const QString &output, cardDir.entryList({"*-*"}, QDir::Dirs)) { QFile edidFile(cardDir.filePath(output + "/edid")); if (edidFile.open(QIODevice::ReadOnly)) { QByteArray data = edidFile.readAll(); if (!data.isEmpty()) { qInfo() << "output:" << output << " edid:" << data.toHex().toUpper(); edidMap.insert(output, data.toHex().toUpper()); } } } } return edidMap; } // 对比EDID关键字段 static bool compareKeyFields(const QByteArray ¤t, const QByteArray &known) { if (current.size() < 16 || known.size() < 16) { qWarning() << "EDID长度不足,无法比较"; return false; } // 厂商ID(字节8-9) // if (current.mid(16,4) != known.mid(16,4)) return false; // 2字节转4字符hex // 产品代码(字节10-11) if (current.mid(20,4) != known.mid(20,4)) { qDebug() << "比较产品代码:" << current.mid(20,4) << "vs" << known.mid(20,4); return false; } // 出厂周/年(字节16-17) // if (current.mid(32,4) != known.mid(32,4)) return false; return true; } // 完整EDID对比 static bool compareFullEdid(const QByteArray ¤t, const QByteArray &known) { return (current == known); } static bool isSameScreen() { const QByteArray EDO_EDID = "00FFFFFFFFFFFF00148F28140000000015230104B51E1378" "02A521AE513CB9240A4F53000000010101010101010101010" "1010101010183DB4074B10838743004C14C2EBD1000001883D" "B4074B10878703004C14C2EBD10000018000000FE0045444F2" "053480A202020202020000000FE004545303051424136332E2" "0440A0002"; const QByteArray EDO_EDID_1 = "00FFFFFFFFFFFF00148F28140000000015230104B51E1378" "02A521AE513CB9240A4F53000000010101010101010101010" "1010101010183DB4074B10838743004C14C2EBD1000001883D" "B4074B10878703004C14C2EBD10000018000000FE0045444F2" "053480A202020202020000000FE004545303051424136332E4" "40A200002"; const QByteArray ATNA_EDID = "00ffffffffffff004c839f4100000000" "00210104b51e1378020cf1ae523cb923" "0c505400000001010101010101010101" "010101010101cafe4064b00818702008" "88002ebd1000001bcafe4064b0083877" "082088002ebd1000001b000000fe0053" "444320202020202020202020000000fe" "0041544e413430594b32302d302001cf" "02030f00e3058000e606050174600700" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "000000000000000000000000000000b7"; // 华星EDID const QByteArray HX_EDID = "00ffffffffffff000e77641400000000" "00230104b51e1378e32d0ea4554c9b25" "0d4e5300000001010101010101010101" "010101010101178840a0b0086e703020" "36002dbc10000018000000fd002878e6" "e646010a202020202020000000fe0043" "534f542054330a2020202020000000fc" "004d4e453030375a41332d370a200124" "7020790200200018408bf66414000000" "0000190c4d4e453030375a41332d370a" "21001dc70b5d07400b0807004dfa54cc" "e49b49020d023554d05fd05f00341378" "220014c1a10a053f0b9f002f001f0007" "076d00020005002b000c270028770000" "2700283b0000810014731a0000035128" "7800000000000078000000008d006690"; // 天马EDID const QByteArray TM_EDID = "00ffffffffffff0051a1562000000000" "16230104b51e13780766e5a3534c9824" "10505400000001010101010101010101" "010101010101988640a0b00859703020" "36002cbe10000018000000fd002878e3" "e345010a20202020202000000010000a" "202020202020202020202020000000fc" "00544c3134304144585032320a2001dd" "702079020020000c0000005620000000" "0016190021001dc80b5d07400b080740" "348a53c484984c821004455400000000" "00001378260009040000000000010000" "220014d5830a053f0b9f002f001f0007" "075800020005002b000c270028770000" "2700283b0000810015741a0000030128" "7800006041604178000000008d008390"; qInfo() << "EDO_EDID :" << EDO_EDID; qInfo() << "ATNA_EDID :" << ATNA_EDID; // 获取当前EDID QMap currentEdids = EdidComparator::readCurrentEdids(); // 对比逻辑 foreach (const QByteArray &edid, currentEdids) { if (EdidComparator::compareFullEdid(edid.toUpper(), EDO_EDID) || EdidComparator::compareFullEdid(edid.toLower(), ATNA_EDID) || EdidComparator::compareFullEdid(edid.toUpper(), EDO_EDID_1) || EdidComparator::compareKeyFields(edid.toLower(), HX_EDID) || EdidComparator::compareKeyFields(edid.toLower(), TM_EDID) ) { qInfo() << "是同一屏幕"; return true; } } return false; } }; #endif // HARDWAREREADER_H ukui-power-manager/registeredQDbus/hardware-reader/hardwarereader.cpp0000664000175000017500000001014415167661430025045 0ustar fengfeng/* * Copyright 2025 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "hardwarereader.h" #include #include #include HardwareReader* HardwareReader::m_instance = nullptr; HardwareReader* HardwareReader::instance() { if (!m_instance) { m_instance = new HardwareReader(); } return m_instance; } HardwareReader::HardwareReader() { // 初始化CPU信息 getCpuType(); } HardwareReader::~HardwareReader() { } bool HardwareReader::isFlemingX() { QString productName = getSystemProductName(); bool result = productName.contains("L420x", Qt::CaseInsensitive); qDebug() << "Hardware detection - Product name:" << productName << "Is FlemingX:" << result; return result; } QString HardwareReader::getSystemProductName() { return executeCommand("dmidecode -s system-product-name").trimmed(); } bool HardwareReader::isPgwDevice() const { // 使用dmidecode读取OEM String 4 QString output = executeCommand("dmidecode -t 11"); // 检查输出是否为空 if (output.isEmpty()) { qWarning() << "dmidecode command returned empty output"; return false; } // 解析输出并查找PWC30标识 QStringList lines = output.split('\n'); bool foundString4 = false; for (const QString &line : lines) { if (line.contains("String 4:")) { foundString4 = true; qDebug() << "Found OEM String 4:" << line.trimmed(); if (line.contains("PWC30", Qt::CaseInsensitive)) { qDebug() << "PGW device detected with PWC30 identifier"; return true; } } } // 记录未找到String 4的情况 if (!foundString4) { qDebug() << "OEM String 4 not found in dmidecode output"; } return false; } QString HardwareReader::executeCommand(const QString &command) const { QProcess process; // 步骤1: 启动进程并设置超时 process.start("bash", QStringList() << "-c" << command); // 等待进程完成,添加超时处理(5秒) if (!process.waitForFinished(5000)) { qWarning() << "Command execution timed out:" << command; return QString(); } // 步骤2: 处理结果 // 检查是否执行成功 if (process.exitCode() != 0) { qWarning() << "Command execution failed:" << command; qWarning() << "Error:" << process.readAllStandardError(); return QString(); } // 读取并返回结果 return process.readAllStandardOutput(); } void HardwareReader::getCpuType() { if (false == readFile(UPM_CPU_INFO_FILE, m_cpuType)) { qDebug() << "get cpu info failed"; } } bool HardwareReader::readFile(const QString &filePath, QString &content) { QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "read file error :" << filePath; return false; } content = file.readAll(); file.close(); return true; } bool HardwareReader::isPanguM900() const { return m_cpuType.contains("PANGU M900", Qt::CaseInsensitive); } QString HardwareReader::getDMIInfo(const QString field) const { QFile file(DMI_PATH + field); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "file " + DMI_PATH + field + " not exist!"; return QString(); } QString value; value = file.readAll(); file.close(); value.remove('\n'); qInfo() << "get DMIInfo " << field << " is " << value; return value; } ukui-power-manager/registeredQDbus/conf/0000775000175000017500000000000015167661430017251 5ustar fengfengukui-power-manager/registeredQDbus/conf/org.ukui.powermanagement.yaml0000664000175000017500000000053015167661430025066 0ustar fengfengorg:ukui:powermanagement: 1.0.0.1: audit: _type: b _default: false whitelist: _type: as _default: '["/usr/bin/ukui-powermanagement","/usr/bin/ukui-power-manager-tray","/usr/bin/ukui-settings-daemon","/usr/bin/ukui-control-center","/usr/bin/powersaver/exe/powersaver","/usr/bin/gdbus","/usr/bin/ukui-sidebar"]' ukui-power-manager/registeredQDbus/conf/upm-hardware-global.conf0000664000175000017500000000013215167661430023746 0ustar fengfeng[this_product] firstRun=1 [ignore-brightness-node] boardName = ":rnLXCF-ZXE-ZX200-mATX:" ukui-power-manager/registeredQDbus/conf/org.ukui.powermanagement.service0000664000175000017500000000014315167661415025567 0ustar fengfeng[D-BUS Service] Name=org.ukui.powermanagement Exec=/usr/bin/ukui-powermanagement-service User=root ukui-power-manager/registeredQDbus/conf/org.ukui.powermanagement.conf0000664000175000017500000000162515167661415025062 0ustar fengfeng ukui-power-manager/registeredQDbus/upmcommonfile.cpp0000664000175000017500000000332115167661430021701 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "upmcommonfile.h" #include #include #include UpmCommonFile::UpmCommonFile(QObject *parent) : QObject(parent) {} bool UpmCommonFile::read(const QString &filePath, const QString &fileName, QString &content) { QFile file(filePath + fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "read file error :" << filePath + fileName; return false; } content = file.readLine(); file.close(); return true; } bool UpmCommonFile::write(const QString &filePath, const QString &fileName, const QString &content) { QFile file(filePath + fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << "write file error :" << filePath + fileName; return false; } QTextStream in(&file); in << content << Qt::endl; file.close(); return true; } bool UpmCommonFile::exists(const QString &filePath, const QString &fileName) { QFile file(filePath + fileName); return file.exists(); } ukui-power-manager/registeredQDbus/hardware-power-control/0000775000175000017500000000000015167661430022731 5ustar fengfengukui-power-manager/registeredQDbus/hardware-power-control/hardwarepowercontrol.h0000664000175000017500000000403015167661430027352 0ustar fengfeng/* * Copyright 2024 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef HARDWAREPOWERCONTROL_H #define HARDWAREPOWERCONTROL_H #include #define GPU_DEVICES_PATH "/sys/class/drm/card0/device/" #define GPU_DEVICE0_PATH "/sys/class/devfreq/devfreq0/" #define GPU_DEVICE1_PATH "/sys/class/devfreq/devfreq1/" #define GPU_POWER_DPM_STATE "power_dpm_state" #define GPU_POWER_GOVERNOR "governor" #define GPU_POWER_DPM_LEVEL "power_dpm_force_performance_level" #define INTEL_AUDIO_PATH "/sys/module/snd_hda_intel/parameters/" #define INTEL_AUDIO_FILE "power_save" #define PCIE_ASPM_PATH "/sys/module/pcie_aspm/parameters/" #define PCIE_ASPM_FILE "policy" class HardwarePowerControl : public QObject { Q_OBJECT public: explicit HardwarePowerControl(QObject *parent = nullptr); ~HardwarePowerControl(); void setGpuFrequencyMode(const int policy); void setAudioMode(const int policy); void setPcieAspmMode(const int policy); private: QStringList m_gpuPowerDpmState = {"performance", "balanced", "battery"}; QStringList m_gpuPowerDpmLevel = {"high", "auto", "low"}; QStringList m_intelAudioMode = {"0", "1", "1"}; QStringList m_gpuPowerGovernor = {"performance", "simple_ondemand", "powersave"}; void initGpuFrequencyState(); void initGpuFrequencyLevel(); void initIntelAudioMode(); signals: }; #endif // HARDWAREPOWERCONTROL_H ukui-power-manager/registeredQDbus/hardware-power-control/hardwarepowercontrol.cpp0000664000175000017500000001120315167661430027705 0ustar fengfeng/* * Copyright 2024 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "hardwarepowercontrol.h" #include "../upmcommonfile.h" #include "../upmcustomhardwareconfig.h" enum system_policy { system_policy_performance = 0, system_policy_balance, system_policy_powersave, system_policy_max }; HardwarePowerControl::HardwarePowerControl(QObject *parent) : QObject(parent) { initGpuFrequencyState(); initGpuFrequencyLevel(); initIntelAudioMode(); } HardwarePowerControl::~HardwarePowerControl() {} void HardwarePowerControl::initGpuFrequencyState() { QString config; if (true == UpmCustomHardwareConfig::self()->getExtendConfig( UPM_KEY_EXTEND_GPU_FREQUENCY_STATE, config)) { QStringList gpuPowerDpmState = config.split("-"); if (system_policy_max == gpuPowerDpmState.size()) { m_gpuPowerDpmState[system_policy_performance] = gpuPowerDpmState[system_policy_performance]; m_gpuPowerDpmState[system_policy_balance] = gpuPowerDpmState[system_policy_balance]; m_gpuPowerDpmState[system_policy_powersave] = gpuPowerDpmState[system_policy_powersave]; } } } void HardwarePowerControl::initGpuFrequencyLevel() { QString config; if (true == UpmCustomHardwareConfig::self()->getExtendConfig( UPM_KEY_EXTEND_GPU_FREQUENCY_LEVEL, config)) { QStringList gpuPowerDpmLevel = config.split("-"); if (system_policy_max == gpuPowerDpmLevel.size()) { m_gpuPowerDpmLevel[system_policy_performance] = gpuPowerDpmLevel[system_policy_performance]; m_gpuPowerDpmLevel[system_policy_balance] = gpuPowerDpmLevel[system_policy_balance]; m_gpuPowerDpmLevel[system_policy_powersave] = gpuPowerDpmLevel[system_policy_powersave]; } } } void HardwarePowerControl::initIntelAudioMode() { QString config; if (true == UpmCustomHardwareConfig::self()->getExtendConfig( UPM_KEY_EXTEND_INTEL_AUDIO_MODE, config)) { QStringList intelAudioMode = config.split("-"); if (system_policy_max == intelAudioMode.size()) { m_intelAudioMode[system_policy_performance] = intelAudioMode[system_policy_performance]; m_intelAudioMode[system_policy_balance] = intelAudioMode[system_policy_balance]; m_intelAudioMode[system_policy_powersave] = intelAudioMode[system_policy_powersave]; } } } void HardwarePowerControl::setGpuFrequencyMode(const int policy) { if (policy < system_policy_performance || policy > system_policy_powersave) { return ; } if (true == UpmCommonFile::exists(GPU_DEVICE0_PATH, GPU_POWER_GOVERNOR)) { UpmCommonFile::write(GPU_DEVICE0_PATH, GPU_POWER_GOVERNOR, m_gpuPowerGovernor[policy]); } if (true == UpmCommonFile::exists(GPU_DEVICE1_PATH, GPU_POWER_GOVERNOR)) { UpmCommonFile::write(GPU_DEVICE1_PATH, GPU_POWER_GOVERNOR, m_gpuPowerGovernor[policy]); } if (true == UpmCommonFile::exists(GPU_DEVICES_PATH, GPU_POWER_DPM_STATE)) { UpmCommonFile::write(GPU_DEVICES_PATH, GPU_POWER_DPM_STATE, m_gpuPowerDpmState[policy]); } if (true == UpmCommonFile::exists(GPU_DEVICES_PATH, GPU_POWER_DPM_LEVEL)) { UpmCommonFile::write(GPU_DEVICES_PATH, GPU_POWER_DPM_LEVEL, m_gpuPowerDpmLevel[policy]); } } void HardwarePowerControl::setAudioMode(const int policy) { if (policy < system_policy_performance || policy > system_policy_powersave) { return ; } UpmCommonFile::write(INTEL_AUDIO_PATH, INTEL_AUDIO_FILE, m_intelAudioMode[policy]); } void HardwarePowerControl::setPcieAspmMode(const int policy) { QStringList pcieAspmMode; if(true == UpmCustomHardwareConfig::self()->isHygonCpu()) { pcieAspmMode = QStringList{"performance", "default","powersave"}; } else { pcieAspmMode = QStringList{"default", "powersave", "powersave"}; } if (policy < system_policy_performance || policy > system_policy_powersave) { return ; } UpmCommonFile::write(PCIE_ASPM_PATH, PCIE_ASPM_FILE, pcieAspmMode[policy]); } ukui-power-manager/registeredQDbus/dev-power-control/0000775000175000017500000000000015167661430021712 5ustar fengfengukui-power-manager/registeredQDbus/dev-power-control/pcidevice.h0000664000175000017500000000330215167661430024014 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PCIDEVICE_H #define PCIDEVICE_H #include #include #include "devicepowerinfo.h" extern "C"{ #include "pci/pci.h" } #define PCI_DEVICE_PATH "/sys/bus/pci/devices/" #define PCI_BLOCK_DEVICE_PATH "/sys/block/" class PciDevice : public QObject { Q_OBJECT public: explicit PciDevice(QObject *parent = nullptr); signals: private: QVector m_devicePowerInfo; QString m_controlFile; void getPCIDevicePowerInfo(); void getAtaDevicePowerInfo(const QString &parentDir); void getBlockDevicePowerInfo(); bool deviceHasRuntimePM(const QString &devPath); QString lookupPciDeviceName(const QString &devPath); public: int getPCIDeviceNum(); QString getDeviceName(int deviceIndex); QString getCurrentPowerStat(int deviceIndex); QString getDefaultPowerStat(int deviceIndex); bool setPowerStat(int deviceIndex, const QString &stat); bool setAllDevicePowerStat(const QString &stat); void printAllDeviceInfo(); }; #endif // PCIDEVICE_H ukui-power-manager/registeredQDbus/dev-power-control/pcidevice.cpp0000664000175000017500000001401315167661430024350 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "pcidevice.h" static struct pci_access *g_pciAccess = NULL; PciDevice::PciDevice(QObject *parent) : QObject(parent) { m_controlFile = QString("/power/control"); getPCIDevicePowerInfo(); getBlockDevicePowerInfo(); } void PciDevice::getAtaDevicePowerInfo(const QString &parentDir) { QDir ataDeviceDir(parentDir); if(!ataDeviceDir.exists()) { return; } QStringList ataDeviceDirs = ataDeviceDir.entryList(QDir::Dirs).filter("ata"); for (int i = 0; i < ataDeviceDirs.size(); ++i) { QString devicePath = parentDir + '/' + ataDeviceDirs.at(i); if (true == deviceHasRuntimePM(devicePath)) { QString devName = lookupPciDeviceName(devicePath); m_devicePowerInfo.push_back(new DevicePowerInfo("pci-ata", devicePath, devName, m_controlFile, this)); } } } void PciDevice::getPCIDevicePowerInfo() { QDir deviceDir(PCI_DEVICE_PATH); if(!deviceDir.exists()) { return; } QStringList deviceDirs = deviceDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); for (int i = 0; i < deviceDirs.size(); ++i) { QString devicePath = PCI_DEVICE_PATH + deviceDirs.at(i); if (true == deviceHasRuntimePM(devicePath)) { QString devName = lookupPciDeviceName(devicePath); m_devicePowerInfo.push_back(new DevicePowerInfo("pci", devicePath, devName, m_controlFile, this)); } getAtaDevicePowerInfo(devicePath); } } void PciDevice::getBlockDevicePowerInfo() { QDir blockDeviceDir(PCI_BLOCK_DEVICE_PATH); if(!blockDeviceDir.exists()) { return; } QStringList blockDeviceDirs = blockDeviceDir.entryList(QDir::Dirs).filter("sd"); for (int i = 0; i < blockDeviceDirs.size(); ++i) { QString controlFilePath = PCI_BLOCK_DEVICE_PATH + blockDeviceDirs.at(i) + "/device"; if (true == deviceHasRuntimePM(controlFilePath)) { m_devicePowerInfo.push_back(new DevicePowerInfo("pci-block", controlFilePath, blockDeviceDirs.at(i), m_controlFile, this)); } } } bool PciDevice::deviceHasRuntimePM(const QString &devPath) { QFile pmFile(devPath + m_controlFile); if (!pmFile.exists()) { return false; } pmFile.setFileName(devPath + "/power/runtime_suspended_time"); if (!pmFile.open(QIODevice::ReadOnly | QIODevice::Text)) { qCritical() << "open file error:" << pmFile.fileName(); return false; } ulong value = pmFile.readLine().toULong(); pmFile.close(); if (value) { return true; } pmFile.setFileName(devPath + "/power/runtime_active_time"); if (!pmFile.open(QIODevice::ReadOnly | QIODevice::Text)) { qCritical() << "open file error:" << pmFile.fileName(); return false; } value = pmFile.readLine().toULong(); pmFile.close(); if (value) { return true; } return false; } QString PciDevice::lookupPciDeviceName(const QString &devPath) { ulong vendorId = 0; ulong deviceId = 0; bool ok; QFile file(devPath + "/vendor"); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { vendorId = file.readLine().toULong(&ok, 16); file.close(); } file.setFileName(devPath + "/device"); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { deviceId = file.readLine().toULong(&ok, 16); file.close(); } char devName[512] = {0}; char *pDevName = NULL; if (NULL == g_pciAccess) { g_pciAccess = pci_alloc(); pci_init(g_pciAccess); } pDevName = pci_lookup_name(g_pciAccess, devName, 512, PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, vendorId, deviceId); return QString(pDevName); } int PciDevice::getPCIDeviceNum() { return m_devicePowerInfo.count(); } QString PciDevice::getDeviceName(int deviceIndex) { if (deviceIndex < m_devicePowerInfo.count()) { return m_devicePowerInfo[deviceIndex]->getDeviceName(); } return "False"; } QString PciDevice::getCurrentPowerStat(int deviceIndex) { if (deviceIndex < m_devicePowerInfo.count()) { return m_devicePowerInfo[deviceIndex]->getCurrentPowerStat(); } return "False"; } QString PciDevice::getDefaultPowerStat(int deviceIndex) { if (deviceIndex < m_devicePowerInfo.count()) { return m_devicePowerInfo[deviceIndex]->getDefaultPowerStat(); } return "False"; } bool PciDevice::setPowerStat(int deviceIndex, const QString &stat) { if (stat == "auto" || stat == "on" || stat == "default") { if (deviceIndex < m_devicePowerInfo.count()) { return m_devicePowerInfo[deviceIndex]->setDevicePowerStat(stat); } } return false; } bool PciDevice::setAllDevicePowerStat(const QString &stat) { if (stat == "auto" || stat == "on" || stat == "default") { for (int i = 0; i < m_devicePowerInfo.count(); ++i) { m_devicePowerInfo[i]->setDevicePowerStat(stat); } return true; } return false; } void PciDevice::printAllDeviceInfo() { qDebug() << "pci device"; for (int i = 0; i < m_devicePowerInfo.count(); ++i) { qDebug() << "name:" << m_devicePowerInfo[i]->getDeviceName() << "path:" << m_devicePowerInfo[i]->getDevicePath() << "stat:" << m_devicePowerInfo[i]->getDefaultPowerStat(); } } ukui-power-manager/registeredQDbus/dev-power-control/i2cdevice.cpp0000664000175000017500000001062415167661430024256 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "i2cdevice.h" I2cDevice::I2cDevice(QObject *parent) : QObject(parent) { m_controlFile = QString("/power/control"); getDevicePowerInfo(); } void I2cDevice::getDevicePowerInfo() { QDir deviceDir(I2C_DEVICE_PATH); if(!deviceDir.exists()) { return; } QStringList deviceDirs = deviceDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); QString devicePath; for (int i = 0; i < deviceDirs.size(); ++i) { devicePath = I2C_DEVICE_PATH + deviceDirs.at(i); QString devName = getI2cDeviceName(devicePath); QFile pmControlFile(devicePath + "/new_device"); if (pmControlFile.exists()) { devicePath.append("/device"); } if (true == deviceHasRuntimePM(devicePath)) { m_devicePowerInfo.push_back(new DevicePowerInfo("i2c", devicePath, devName, m_controlFile, this)); } } } bool I2cDevice::deviceHasRuntimePM(const QString &devPath) { QFile pmFile(devPath + m_controlFile); if (!pmFile.exists()) { return false; } pmFile.setFileName(devPath + "/power/runtime_suspended_time"); if (!pmFile.open(QIODevice::ReadOnly | QIODevice::Text)) { qCritical() << "open file error:" << pmFile.fileName(); return false; } ulong value = pmFile.readLine().toULong(); pmFile.close(); if (value) { return true; } pmFile.setFileName(devPath + "/power/runtime_active_time"); if (!pmFile.open(QIODevice::ReadOnly | QIODevice::Text)) { qCritical() << "open file error:" << pmFile.fileName(); return false; } value = pmFile.readLine().toULong(); pmFile.close(); if (value) { return true; } return false; } QString I2cDevice::getI2cDeviceName(const QString &devPath) { QString deviceName; QFile file(devPath + "/name"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qCritical() << "open file error:" << file.fileName(); return "unknown"; } deviceName = file.readLine(); file.close(); return deviceName.remove('\n'); } int I2cDevice::getPCIDeviceNum() { return m_devicePowerInfo.count(); } QString I2cDevice::getDeviceName(int deviceIndex) { if (deviceIndex < m_devicePowerInfo.count()) { return m_devicePowerInfo[deviceIndex]->getDeviceName(); } return "False"; } QString I2cDevice::getCurrentPowerStat(int deviceIndex) { if (deviceIndex < m_devicePowerInfo.count()) { return m_devicePowerInfo[deviceIndex]->getCurrentPowerStat(); } return "False"; } QString I2cDevice::getDefaultPowerStat(int deviceIndex) { if (deviceIndex < m_devicePowerInfo.count()) { return m_devicePowerInfo[deviceIndex]->getDefaultPowerStat(); } return "False"; } bool I2cDevice::setPowerStat(int deviceIndex, const QString &stat) { if (stat == "auto" || stat == "on" || stat == "default") { if (deviceIndex < m_devicePowerInfo.count()) { return m_devicePowerInfo[deviceIndex]->setDevicePowerStat(stat); } } return false; } bool I2cDevice::setAllDevicePowerStat(const QString &stat) { if (stat == "auto" || stat == "on" || stat == "default") { for (int i = 0; i < m_devicePowerInfo.count(); ++i) { m_devicePowerInfo[i]->setDevicePowerStat(stat); } return true; } return false; } void I2cDevice::printAllDeviceInfo() { qDebug() << "i2c device"; for (int i = 0; i < m_devicePowerInfo.count(); ++i) { qDebug() << "name:" << m_devicePowerInfo[i]->getDeviceName() << "path:" << m_devicePowerInfo[i]->getDevicePath() << "stat:" << m_devicePowerInfo[i]->getDefaultPowerStat(); } } ukui-power-manager/registeredQDbus/dev-power-control/devicepowerinfo.cpp0000664000175000017500000000615315167661430025613 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "devicepowerinfo.h" DevicePowerInfo::DevicePowerInfo(const QString &devType, const QString &devPath, const QString &devName, const QString &controlFile, QObject *parent) : QObject(parent), m_devType(devType), m_devPath(devPath), m_devName(devName) { m_powerControlFilePath = devPath + controlFile; QFile file(m_powerControlFilePath); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream textStream(&file); m_defaultPowerValue = textStream.readLine(); m_currentPowerValue = m_defaultPowerValue; file.close(); } } QString DevicePowerInfo::getDevicePath() { return m_devPath; } QString DevicePowerInfo::getDeviceName() { return m_devName; } QString DevicePowerInfo::getCurrentPowerStat() { return m_currentPowerValue; } QString DevicePowerInfo::getDefaultPowerStat() { return m_defaultPowerValue; } bool DevicePowerInfo::ignoreDeviceList() { if (m_devType == "pci") { if (m_devName.contains("Ethernet", Qt::CaseInsensitive)) { return true; } if (m_devName.contains("usb", Qt::CaseInsensitive)) { return true; } } return false; } bool DevicePowerInfo::setDevicePowerStat(const QString &stat) { bool ret = false; if (true == ignoreDeviceList()) { return false; } QFile controlFile(m_powerControlFilePath); if (!controlFile.open(QIODevice::WriteOnly | QIODevice::Text)) { return false; } QTextStream in(&controlFile); if (stat == "default") { in << m_defaultPowerValue << Qt::endl; m_currentPowerValue = m_defaultPowerValue; ret = true; } else { if (m_devType == "sata") { if (stat == "min_power" || stat == "max_performance") { in << stat << Qt::endl; m_currentPowerValue = stat; ret = true; } else { ret = false; } } else { if (stat == "auto" || stat == "on") { in << stat << Qt::endl; m_currentPowerValue = stat; ret = true; } else { ret = false; } } } controlFile.close(); return ret; } ukui-power-manager/registeredQDbus/dev-power-control/satadevice.h0000664000175000017500000000303515167661430024174 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SATADEVICE_H #define SATADEVICE_H #include #include #include "devicepowerinfo.h" #define SATA_DEVICE_PATH "/sys/class/scsi_host/" class SataDevice : public QObject { Q_OBJECT public: explicit SataDevice(QObject *parent = nullptr); signals: private: QVector m_devicePowerInfo; QString m_controlFile; void getDevicePowerInfo(); bool checkUsbSupportAutosuspend(const QString &devPath); QString getSataDeviceName(const QString &devPath); public: int getPCIDeviceNum(); QString getDeviceName(int deviceIndex); QString getCurrentPowerStat(int deviceIndex); QString getDefaultPowerStat(int deviceIndex); bool setPowerStat(int deviceIndex, const QString &stat); bool setAllDevicePowerStat(const QString &stat); void printAllDeviceInfo(); }; #endif // SATADEVICE_H ukui-power-manager/registeredQDbus/dev-power-control/devicepowerinfo.h0000664000175000017500000000307215167661430025255 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DEVICEPOWERINFO_H #define DEVICEPOWERINFO_H #include class DevicePowerInfo : public QObject { Q_OBJECT public: explicit DevicePowerInfo(const QString &devType, const QString &devPath, const QString &devName, const QString &controlFile, QObject *parent = nullptr); signals: private: QString m_devType; QString m_devPath; QString m_powerControlFilePath; QString m_devName; QString m_defaultPowerValue; QString m_currentPowerValue; bool ignoreDeviceList(); public: QString getDevicePath(); QString getDeviceName(); QString getCurrentPowerStat(); QString getDefaultPowerStat(); void setDevName(const QString &devName); bool setDevicePowerStat(const QString &stat); }; #endif // DEVICEPOWERINFO_H ukui-power-manager/registeredQDbus/dev-power-control/devpowercontrol.h0000664000175000017500000000243315167661430025321 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DEVPOWERCONTROL_H #define DEVPOWERCONTROL_H #include #include "pcidevice.h" #include "i2cdevice.h" #include "satadevice.h" #include "../upmcustomhardwareconfig.h" class DevPowerControl : public QObject { Q_OBJECT public: explicit DevPowerControl(QObject *parent = nullptr); ~DevPowerControl(); void setAllDevicePerformance(); void setAllDeviceBalance(); void setAllDeviceSave(); private: void setAllDevice(QString mode); private: PciDevice *m_pci = nullptr; I2cDevice *m_i2c = nullptr; SataDevice *m_sata = nullptr; }; #endif // DEVPOWERCONTROL_H ukui-power-manager/registeredQDbus/dev-power-control/satadevice.cpp0000664000175000017500000000633215167661430024532 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "satadevice.h" SataDevice::SataDevice(QObject *parent) : QObject(parent) { m_controlFile = QString("/link_power_management_policy"); getDevicePowerInfo(); } void SataDevice::getDevicePowerInfo() { QDir deviceDir(SATA_DEVICE_PATH); if(!deviceDir.exists()) { return; } QStringList deviceDirs = deviceDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); QString devicePath; QFile pmControlFile; for (int i = 0; i < deviceDirs.size(); ++i) { devicePath = SATA_DEVICE_PATH + deviceDirs.at(i); pmControlFile.setFileName(devicePath + m_controlFile); if (!pmControlFile.exists()) { continue; } QString devName = QString("STAT link PM " + deviceDirs.at(i)); m_devicePowerInfo.push_back(new DevicePowerInfo("sata", devicePath, devName, m_controlFile, this)); } } int SataDevice::getPCIDeviceNum() { return m_devicePowerInfo.count(); } QString SataDevice::getDeviceName(int deviceIndex) { if (deviceIndex < m_devicePowerInfo.count()) { return m_devicePowerInfo[deviceIndex]->getDeviceName(); } return "False"; } QString SataDevice::getCurrentPowerStat(int deviceIndex) { if (deviceIndex < m_devicePowerInfo.count()) { return m_devicePowerInfo[deviceIndex]->getCurrentPowerStat(); } return "False"; } QString SataDevice::getDefaultPowerStat(int deviceIndex) { if (deviceIndex < m_devicePowerInfo.count()) { return m_devicePowerInfo[deviceIndex]->getDefaultPowerStat(); } return "False"; } bool SataDevice::setPowerStat(int deviceIndex, const QString &stat) { if (stat == "min_power" || stat == "max_performance" || stat == "default") { if (deviceIndex < m_devicePowerInfo.count()) { return m_devicePowerInfo[deviceIndex]->setDevicePowerStat(stat); } } return false; } bool SataDevice::setAllDevicePowerStat(const QString &stat) { if (stat == "min_power" || stat == "max_performance" || stat == "default") { for (int i = 0; i < m_devicePowerInfo.count(); ++i) { m_devicePowerInfo[i]->setDevicePowerStat(stat); } return true; } return false; } void SataDevice::printAllDeviceInfo() { qDebug() << "stat device"; for (int i = 0; i < m_devicePowerInfo.count(); ++i) { qDebug() << "name:" << m_devicePowerInfo[i]->getDeviceName() << "path:" << m_devicePowerInfo[i]->getDevicePath() << "stat:" << m_devicePowerInfo[i]->getDefaultPowerStat(); } } ukui-power-manager/registeredQDbus/dev-power-control/devpowercontrol.cpp0000664000175000017500000000374715167661430025665 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "devpowercontrol.h" DevPowerControl::DevPowerControl(QObject *parent) : QObject(parent) { QString config; if (true == UpmCustomHardwareConfig::self()->getExtendConfig( UPM_KEY_EXTEND_BUS_DEVICE_AUTO_SUSPEND, config)) { if (true == config.contains("pci")) { m_pci = new PciDevice(this); } if (true == config.contains("sata")) { m_sata = new SataDevice(this); } if (true == config.contains("iic")) { m_i2c = new I2cDevice(this); } } } DevPowerControl::~DevPowerControl() {} void DevPowerControl::setAllDevicePerformance() { setAllDevice("on"); } void DevPowerControl::setAllDeviceBalance() { setAllDevice("default"); } void DevPowerControl::setAllDeviceSave() { setAllDevice("auto"); } void DevPowerControl::setAllDevice(QString mode) { if (m_pci != nullptr) { m_pci->setAllDevicePowerStat(mode); } if (m_i2c != nullptr) { m_i2c->setAllDevicePowerStat(mode); } if (m_sata != nullptr) { if (mode == "on") { m_sata->setAllDevicePowerStat("max_performance"); } else if (mode == "auto") { m_sata->setAllDevicePowerStat("min_power"); } else { m_sata->setAllDevicePowerStat(mode); } } } ukui-power-manager/registeredQDbus/dev-power-control/i2cdevice.h0000664000175000017500000000301515167661430023717 0ustar fengfeng/* * Copyright 2023 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef I2CDEVICE_H #define I2CDEVICE_H #include #include #include "devicepowerinfo.h" #define I2C_DEVICE_PATH "/sys/bus/i2c/devices/" class I2cDevice : public QObject { Q_OBJECT public: explicit I2cDevice(QObject *parent = nullptr); signals: private: QVector m_devicePowerInfo; QString m_controlFile; void getDevicePowerInfo(); bool deviceHasRuntimePM(const QString &devPath); QString getI2cDeviceName(const QString &devPath); public: int getPCIDeviceNum(); QString getDeviceName(int deviceIndex); QString getCurrentPowerStat(int deviceIndex); QString getDefaultPowerStat(int deviceIndex); bool setPowerStat(int deviceIndex, const QString &stat); bool setAllDevicePowerStat(const QString &stat); void printAllDeviceInfo(); }; #endif // I2CDEVICE_H ukui-power-manager/registeredQDbus/syslog-handler.hpp0000664000175000017500000000422715167661430021775 0ustar fengfeng/* * Copyright 2024 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SYSLOGHANDLER_HPP #define SYSLOGHANDLER_HPP #include #include #include #include #include #include class SyslogHandler { public: static void staticMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { QMutexLocker locker(&mutex); int syslogPriority; switch (type) { case QtDebugMsg: syslogPriority = LOG_DEBUG; break; case QtInfoMsg: syslogPriority = LOG_INFO; break; case QtWarningMsg: syslogPriority = LOG_WARNING; break; case QtCriticalMsg: syslogPriority = LOG_CRIT; break; case QtFatalMsg: syslogPriority = LOG_ALERT; // abort(); // 通常,QtFatalMsg 会导致程序终止,所以我们在这里也调用 abort() break; default: syslogPriority = LOG_NOTICE; // 默认情况下使用 LOG_NOTICE break; } syslog(syslogPriority, "%s", msg.toUtf8().constData()); } static SyslogHandler* instance() { static SyslogHandler singleton; return &singleton; } private: SyslogHandler() {} // 私有构造函数,防止外部实例化 ~SyslogHandler(); // 私有析构函数,防止外部删除 static QMutex mutex; // 用于线程安全的静态成员变量 }; #endif // SYSLOGHANDLER_HPP ukui-power-manager/registeredQDbus/upmcustomhardwareconfig.h0000664000175000017500000001017115167661430023435 0ustar fengfeng/* * Copyright 2024 KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UPMCUSTOMHARDWARECONFIG_H #define UPMCUSTOMHARDWARECONFIG_H #include #include #define UPM_NO_THIS_KEY QStringLiteral("no-this-key") #define UPM_HARDWARE_INFO_FILE QStringLiteral("/sys/class/dmi/id/modalias") #define UPM_CPU_INFO_FILE QStringLiteral("/proc/cpuinfo") #define UPM_GLOBAL_HARDWARE_CONFIG_FILE QStringLiteral("/usr/share/ukui/ukui-power-manager/upm-hardware-global.conf") #define UPM_EXTEND_HARDWARE_CONFIG_PATH QStringLiteral("/usr/share/ukui/ukui-power-manager/upm-hardware-extend.d/") #define UPM_GROUP_EXTEND_BRAND_GENERIC_CONFIG QStringLiteral("Brand-generic-config") #define UPM_KEY_FIRST_RUN_DONOT_SUSPEND QStringLiteral("firstRunDonotSuspend") #define UPM_KEY_BOARD_NAME QStringLiteral("boardName") #define UPM_GROUP_THIS_PRODUCT QStringLiteral("this_product") #define UPM_KEY_FIRST_RUN QStringLiteral("firstRun") #define UPM_KEY_EXTEND_CONFIG_PATH QStringLiteral("extendConfigPath") #define UPM_KEY_DEVICE_IDENTIFICATION QStringLiteral("deviceIdentification") #define UPM_GROUP_IGNORE_BRIGHTNESS_NODE QStringLiteral("ignore-brightness-node") #define UPM_KEY_EXTEND_BRIGHTNESS_NODE QStringLiteral("brightnessNode") #define UPM_KEY_EXTEND_PERFORMANCE_IDEL_RESERVE_CPU0 QStringLiteral("performanceIdleReserveCpu0") #define UPM_KEY_EXTEND_BALANCE_IDEL_RESERVE_CPU0 QStringLiteral("balanceIdleReserveCpu0") #define UPM_KEY_EXTEND_POWERSAVE_IDEL_RESERVE_CPU0 QStringLiteral("powersaveIdleReserveCpu0") #define UPM_KEY_EXTEND_BALANCE_MODE_REDUCE_FREQUENCY QStringLiteral("balanceModeReduceFrequency") #define UPM_KEY_EXTEND_BALANCE_MODE_MAX_FREQUENCY QStringLiteral("balanceModeMaxFrequency") #define UPM_KEY_EXTEND_PERFORMANCE_AUTO_SWITCH_CPU_CORE QStringLiteral("performanceAutoSwitchCpuCore") #define UPM_KEY_EXTEND_BALANCE_AUTO_SWITCH_CPU_CORE QStringLiteral("balanceAutoSwitchCpuCore") #define UPM_KEY_EXTEND_POWERSAVE_AUTO_SWITCH_CPU_CORE QStringLiteral("powersaveAutoSwitchCpuCore") #define UPM_KEY_EXTEND_BUS_DEVICE_AUTO_SUSPEND QStringLiteral("busDeviceAutoSuspend") #define UPM_KEY_EXTEND_GPU_FREQUENCY_STATE QStringLiteral("gpuFrequencyState") #define UPM_KEY_EXTEND_GPU_FREQUENCY_LEVEL QStringLiteral("gpuFrequencyLevel") #define UPM_KEY_EXTEND_INTEL_AUDIO_MODE QStringLiteral("intelAudioMode") class UpmCustomHardwareConfig : public QObject { Q_OBJECT public: explicit UpmCustomHardwareConfig(QObject *parent = nullptr); ~UpmCustomHardwareConfig(); static UpmCustomHardwareConfig *self(); bool isPanguM900(); bool isHygonCpu(); bool brightnessNodeEffective(); QString getBrightnessNode(); bool firstRunDonotSuspend(); bool getExtendConfig(const QString &configKey, QString &config); private: QString m_hardwareInfo = ""; QString m_cpuType = ""; QSettings *m_globalConfig = nullptr; QSettings *m_extendConfig = nullptr; QString m_productGroup = ""; QString m_extendConfigPath = ""; void getHardwareInfo(); void getCpuType(); bool readConfig(QSettings *settings, const QString &group, const QString &key, QVariant &value); bool getExtendConfigFile(QString &configFilePath); bool readAll(const QString &filePath, QString &content); signals: }; #endif // UPMCUSTOMDEFAULTHARDWARECONFIG_H ukui-power-manager/registeredQDbus/registeredQDbus.pro0000664000175000017500000000412015167661430022137 0ustar fengfengQT += core dbus QT -= gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = ukui-powermanagement-service TEMPLATE = app CONFIG += console c++11 link_pkgconfig CONFIG -= app_bundle LIBS += -lukui-log4qt -lpci DESTDIR = . INCLUDEPATH += . INCLUDEPATH += $$PWD/../shared/include DEFINES += QT_NO_DEBUG_OUTPUT DEFINES += MODULE_NAME=\\\"pm\\\" upmDbusAuthorityControlEtc.files += conf/org.ukui.powermanagement.yaml upmDbusAuthorityControlEtc.path = /usr/share/ukui/ukui-power-manager/ INSTALLS += upmDbusAuthorityControlEtc inst1.files += conf/org.ukui.powermanagement.service inst1.path = /usr/share/dbus-1/system-services/ inst2.files += conf/org.ukui.powermanagement.conf inst2.path = /usr/share/dbus-1/system.d/ target.source += $$TARGET target.path = /usr/bin INSTALLS += target inst1 inst2 upmHardwareGlobalConf.files += conf/upm-hardware-global.conf upmHardwareGlobalConf.path = /usr/share/ukui/ukui-power-manager/ INSTALLS += upmHardwareGlobalConf HEADERS += \ brightness-control/brightnessnode.h \ cpu-control/upmcpucontrol.h \ cpu-control/upmcpucoreinfo.h \ cpu-control/upmcpuoccupy.h \ dev-power-control/devpowercontrol.h \ hardware-power-control/hardwarepowercontrol.h \ powerconfig.h \ sysdbusregister.h \ dev-power-control/devicepowerinfo.h \ dev-power-control/i2cdevice.h \ dev-power-control/pcidevice.h \ dev-power-control/satadevice.h \ syslog-handler.hpp \ upmcommonfile.h \ upmcustomhardwareconfig.h \ hardware-reader/hardwarereader.h SOURCES += \ brightness-control/brightnessnode.cpp \ cpu-control/upmcpucontrol.cpp \ cpu-control/upmcpucoreinfo.cpp \ cpu-control/upmcpuoccupy.cpp \ dev-power-control/devpowercontrol.cpp \ hardware-power-control/hardwarepowercontrol.cpp \ main.cpp \ powerconfig.cpp \ sysdbusregister.cpp \ dev-power-control/devicepowerinfo.cpp \ dev-power-control/i2cdevice.cpp \ dev-power-control/pcidevice.cpp \ dev-power-control/satadevice.cpp \ upmcommonfile.cpp \ upmcustomhardwareconfig.cpp \ hardware-reader/hardwarereader.cpp ukui-power-manager/ukui-power-manager.md0000664000175000017500000000172615167661430017277 0ustar fengfeng1 总览 为了能够更方便的通过图形的方式让用户使用节能方案,延长电池寿命,降温,延长外设使用寿命,桌面环境使用ukui-power-manager来管理电源选项。 针对APM和ACPI两种不同的标准,Linux内核提供了两个不同的模块来实现电源管理功能,这就是apm和acpi。需要注意,apm和acpi是互相冲突的两个模块,用户在同一时间内只能加载其中之一,如果当他们在加载的时候发现二者之一已经加载,就会自动退出。在我们桌面环境中,默认使用的是acpi标准。 2 后台 电源管理后台主要做的功能包括 空闲之后降低亮度、关闭显示器、睡眠休眠等 合盖之后执行关闭显示,睡眠休眠、关机等 插拔电源适配器额时候执行亮度降低,切换模式等 3 托盘界面 通过托盘界面,能够给用户直观的反馈,告知用户充电、放电状态;剩余充电时间、剩余放电时间。 ukui-power-manager/tests/0000775000175000017500000000000015167661430014372 5ustar fengfengukui-power-manager/tests/i2cDeviceTest.cpp0000664000175000017500000000351315167661430017535 0ustar fengfeng#include #include #include #include #include "../registeredQDbus/dev-power-control/i2cdevice.h" class I2cDeviceTest : public ::testing::Test { protected: void SetUp() override { m_tempDir.reset(new QTemporaryDir()); ASSERT_TRUE(m_tempDir->isValid()); setupMockDevice(); m_device = new I2cDevice(); } void TearDown() override { if (m_device) { delete m_device; m_device = nullptr; } m_tempDir.reset(); } void setupMockDevice() { QString basePath = m_tempDir->path(); QDir dir; QString devicePath = basePath + "/sys/bus/i2c/devices/i2c-0"; dir.mkpath(devicePath + "/power"); createMockFile(devicePath + "/power/control", "auto"); createMockFile(devicePath + "/name", "i2c-test-device"); } void createMockFile(const QString &path, const QString &content) { QFile file(path); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { file.write(content.toUtf8()); file.close(); } } QScopedPointer m_tempDir; I2cDevice* m_device{nullptr}; }; // 测试设置所有设备电源状态 TEST_F(I2cDeviceTest, SetAllDevicePowerStatTest) { EXPECT_FALSE(m_device->setAllDevicePowerStat("invalid")); EXPECT_TRUE(m_device->setAllDevicePowerStat("auto")); EXPECT_TRUE(m_device->setAllDevicePowerStat("on")); EXPECT_TRUE(m_device->setAllDevicePowerStat("default")); } // 测试打印设备信息 TEST_F(I2cDeviceTest, PrintDeviceInfoTest) { testing::internal::CaptureStdout(); m_device->printAllDeviceInfo(); std::string output = testing::internal::GetCapturedStdout(); EXPECT_TRUE(output.find("i2c device") != std::string::npos); }ukui-power-manager/tests/devicePowerInfoTest.cpp0000664000175000017500000000433415167661430021032 0ustar fengfeng#include #include #include "../registeredQDbus/dev-power-control/devicepowerinfo.h" class DevicePowerInfoTest : public ::testing::Test { protected: void SetUp() override { m_tempDir.reset(new QTemporaryDir()); ASSERT_TRUE(m_tempDir->isValid()); setupMockDevice(); // 验证测试环境 QDir dir(m_powerPath); ASSERT_TRUE(dir.exists()) << "Power path does not exist: " << m_powerPath.toStdString(); } void setupMockDevice() { QString basePath = m_tempDir->path(); m_devicePath = basePath + "/sys/bus/pci/devices/0000:00:00.0"; m_powerPath = m_devicePath + "/power"; QDir dir; ASSERT_TRUE(dir.mkpath(m_powerPath)); // 创建并验证控制文件 createMockFile(m_powerPath + "/control", "auto"); QFile controlFile(m_powerPath + "/control"); ASSERT_TRUE(controlFile.exists()); } void createMockFile(const QString &path, const QString &content) { QFile file(path); ASSERT_TRUE(file.open(QIODevice::WriteOnly | QIODevice::Text)) << "Failed to create file: " << path.toStdString(); file.write(content.toUtf8()); file.close(); } QScopedPointer m_tempDir; QString m_devicePath; QString m_powerPath; }; TEST_F(DevicePowerInfoTest, SetDevicePowerStatTest) { DevicePowerInfo device("pci", "Test Device", m_devicePath, m_powerPath, nullptr); // 验证设备路径 ASSERT_TRUE(QFile::exists(m_powerPath + "/control")) << "Control file does not exist: " << (m_powerPath + "/control").toStdString(); // 测试有效状态 EXPECT_TRUE(device.setDevicePowerStat("auto")) << "Failed to set power state to auto"; EXPECT_TRUE(device.setDevicePowerStat("on")) << "Failed to set power state to on"; EXPECT_TRUE(device.setDevicePowerStat("default")) << "Failed to set power state to default"; // 测试无效状态 EXPECT_FALSE(device.setDevicePowerStat("invalid")); // 测试无效路径 DevicePowerInfo invalidDevice("pci", "Test Device", "/invalid/path", "/invalid/power", nullptr); EXPECT_FALSE(invalidDevice.setDevicePowerStat("auto")); }ukui-power-manager/tests/main.cpp0000664000175000017500000000020315167661430016015 0ustar fengfeng#include int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }ukui-power-manager/tests/sataDeviceTest.cpp0000664000175000017500000000454415167661430020015 0ustar fengfeng#include #include #include "../registeredQDbus/dev-power-control/satadevice.h" class SataDeviceTest : public ::testing::Test { protected: void SetUp() override { m_tempDir.reset(new QTemporaryDir()); ASSERT_TRUE(m_tempDir->isValid()); setupMockDevice(); m_device = new SataDevice(); } void TearDown() override { if (m_device) { delete m_device; m_device = nullptr; } m_tempDir.reset(); } void setupMockDevice() { QString basePath = m_tempDir->path(); QDir dir; // 创建SATA设备目录结构 for(int i = 0; i < 2; i++) { QString devicePath = basePath + "/sys/class/scsi_host/host" + QString::number(i); dir.mkpath(devicePath); // 创建电源管理策略文件 createMockFile(devicePath + "/link_power_management_policy", "min_power"); } } void createMockFile(const QString &path, const QString &content) { QFile file(path); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { file.write(content.toUtf8()); file.close(); } } QScopedPointer m_tempDir; SataDevice* m_device{nullptr}; }; // 测试设备数量 TEST_F(SataDeviceTest, GetDeviceNumTest) { int count = m_device->getPCIDeviceNum(); EXPECT_GE(count, 0); } // 测试电源状态 TEST_F(SataDeviceTest, PowerStateTest) { if (m_device->getPCIDeviceNum() > 0) { // 测试当前状态 EXPECT_NE(m_device->getCurrentPowerStat(0), "False"); // 测试默认状态 EXPECT_NE(m_device->getDefaultPowerStat(0), "False"); // 测试设置状态 EXPECT_TRUE(m_device->setPowerStat(0, "min_power")); EXPECT_TRUE(m_device->setPowerStat(0, "max_performance")); EXPECT_TRUE(m_device->setPowerStat(0, "default")); EXPECT_FALSE(m_device->setPowerStat(0, "invalid")); } } // 测试设置所有设备电源状态 TEST_F(SataDeviceTest, SetAllDevicePowerStatTest) { EXPECT_TRUE(m_device->setAllDevicePowerStat("min_power")); EXPECT_TRUE(m_device->setAllDevicePowerStat("max_performance")); EXPECT_TRUE(m_device->setAllDevicePowerStat("default")); EXPECT_FALSE(m_device->setAllDevicePowerStat("invalid")); }ukui-power-manager/tests/hardWarePowerControlTest.cpp0000664000175000017500000000262415167661430022055 0ustar fengfeng#include "gtest/gtest.h" #include "../registeredQDbus/hardware-power-control/hardwarepowercontrol.h" class HardwarePowerControlTest : public ::testing::Test { protected: void SetUp() override { hwControl = new HardwarePowerControl(); } void TearDown() override { delete hwControl; } HardwarePowerControl* hwControl{nullptr}; }; // GPU频率模式测试 TEST_F(HardwarePowerControlTest, GpuFrequencyTest) { // 测试有效值 for(int policy = 0; policy <= 2; policy++) { EXPECT_NO_THROW(hwControl->setGpuFrequencyMode(policy)); } // 测试无效值 EXPECT_NO_THROW({ hwControl->setGpuFrequencyMode(-1); hwControl->setGpuFrequencyMode(3); }); } // 音频模式测试 TEST_F(HardwarePowerControlTest, AudioModeTest) { // 测试有效值 for(int policy = 0; policy <= 2; policy++) { EXPECT_NO_THROW(hwControl->setAudioMode(policy)); } // 测试无效值 EXPECT_NO_THROW({ hwControl->setAudioMode(-1); hwControl->setAudioMode(3); }); } // PCIE ASPM模式测试 TEST_F(HardwarePowerControlTest, PcieAspmTest) { // 测试有效值 for(int policy = 0; policy <= 2; policy++) { EXPECT_NO_THROW(hwControl->setPcieAspmMode(policy)); } // 测试无效值 EXPECT_NO_THROW({ hwControl->setPcieAspmMode(-1); hwControl->setPcieAspmMode(3); }); }ukui-power-manager/tests/brightnessnodeTest.cpp0000664000175000017500000000451515167661430020761 0ustar fengfeng#include #include #include #include "../registeredQDbus/brightness-control/brightnessnode.h" class BrightnessNodeTest : public ::testing::Test { protected: void SetUp() override { m_tempDir.reset(new QTemporaryDir()); ASSERT_TRUE(m_tempDir->isValid()); setupMockDevice(); m_node = new BrightnessNode(50); } void TearDown() override { if (m_node) { delete m_node; m_node = nullptr; } m_tempDir.reset(); } void setupMockDevice() { QString basePath = m_tempDir->path() + "/sys/class/backlight/intel_backlight"; QDir dir; ASSERT_TRUE(dir.mkpath(basePath)); createMockFile(basePath + "/max_brightness", "100"); createMockFile(basePath + "/brightness", "50"); createMockFile(basePath + "/type", "firmware"); } void createMockFile(const QString &path, const QString &content) { QFile file(path); ASSERT_TRUE(file.open(QIODevice::WriteOnly | QIODevice::Text)); file.write(content.toUtf8()); file.close(); } QScopedPointer m_tempDir; BrightnessNode* m_node{nullptr}; }; // 测试能否设置亮度 TEST_F(BrightnessNodeTest, CanSetBrightnessTest) { EXPECT_TRUE(m_node->canSetBrightness()); } // 测试亮度百分比设置和获取 TEST_F(BrightnessNodeTest, BrightnessPercentTest) { // 正常范围 m_node->setBrightnessPercent(75); EXPECT_EQ(m_node->getBrightnessPercent(), 75); // 小于最小值 m_node->setBrightnessPercent(1); EXPECT_EQ(m_node->getBrightnessPercent(), 1); // 大于最大值 m_node->setBrightnessPercent(150); EXPECT_EQ(m_node->getBrightnessPercent(), 100); } // 测试最大亮度获取 TEST_F(BrightnessNodeTest, GetMaxBrightnessTest) { EXPECT_EQ(m_node->getMaxBrightness(), 100); } // 测试亮度降低功能 TEST_F(BrightnessNodeTest, ReduceMaxBrightnessTest) { int originalMax = m_node->getMaxBrightness(); // 启用亮度降低 m_node->setReduceMaxBrightness(true); m_node->setBrightnessPercent(100); EXPECT_EQ(m_node->getBrightnessPercent(), 100); // 禁用亮度降低 m_node->setReduceMaxBrightness(false); m_node->setBrightnessPercent(100); EXPECT_EQ(m_node->getBrightnessPercent(), 100); } ukui-power-manager/tests/tests.pro0000664000175000017500000000452415167661430016263 0ustar fengfengQT += core testlib dbus CONFIG += c++11 console link_pkgconfig PKGCONFIG += gsettings-qt SOURCES += \ ../registeredQDbus/sysdbusregister.cpp\ ../registeredQDbus/brightness-control/brightnessnode.cpp \ ../registeredQDbus/cpu-control/upmcpucontrol.cpp \ ../registeredQDbus/cpu-control/upmcpucoreinfo.cpp \ ../registeredQDbus/cpu-control/upmcpuoccupy.cpp \ ../registeredQDbus/dev-power-control/devpowercontrol.cpp \ ../registeredQDbus/hardware-power-control/hardwarepowercontrol.cpp \ ../registeredQDbus/powerconfig.cpp \ ../registeredQDbus/dev-power-control/devicepowerinfo.cpp \ ../registeredQDbus/dev-power-control/i2cdevice.cpp \ ../registeredQDbus/dev-power-control/pcidevice.cpp \ ../registeredQDbus/dev-power-control/satadevice.cpp \ ../registeredQDbus/upmcommonfile.cpp \ ../registeredQDbus/upmcustomhardwareconfig.cpp \ pciDeviceTest.cpp \ upmCpuControlTest.cpp \ sysDbusRegisterTest.cpp \ upmCustomHardwareConfigTest.cpp \ hardWarePowerControlTest.cpp \ devicePowerInfoTest.cpp \ i2cDeviceTest.cpp \ sataDeviceTest.cpp \ brightnessNodeTest.cpp \ main.cpp HEADERS += \ ../registeredQDbus/sysdbusregister.h\ ../registeredQDbus/brightness-control/brightnessnode.h \ ../registeredQDbus/common.h \ ../registeredQDbus/cpu-control/upmcpucontrol.h \ ../registeredQDbus/cpu-control/upmcpucoreinfo.h \ ../registeredQDbus/cpu-control/upmcpuoccupy.h \ ../registeredQDbus/dev-power-control/devpowercontrol.h \ ../registeredQDbus/hardware-power-control/hardwarepowercontrol.h \ ../registeredQDbus/powerconfig.h \ ../registeredQDbus/sysdbusregister.h \ ../registeredQDbus/dev-power-control/devicepowerinfo.h \ ../registeredQDbus/dev-power-control/i2cdevice.h \ ../registeredQDbus/dev-power-control/pcidevice.h \ ../registeredQDbus/dev-power-control/satadevice.h \ ../registeredQDbus/upmcommonfile.h \ ../registeredQDbus/upmcustomhardwareconfig.h LIBS += -L/usr/lib -lgtest -lgtest_main -pthread -lpci INCLUDEPATH += /usr/include/gtest QMAKE_LFLAGS +=-fprofile-arcs -ftest-coverage -fno-access-control QMAKE_CFLAGS += -fprofile-arcs -ftest-coverage -fno-access-control QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage -fno-access-control QMAKE_CXXFLAGS += --coverage CONFIG += link_pkgconfig LIBS += -lgcov ukui-power-manager/tests/upmCpuControlTest.cpp0000664000175000017500000000270315167661430020552 0ustar fengfeng#include "gtest/gtest.h" #include "../registeredQDbus/cpu-control/upmcpucontrol.cpp" class UpmCpuControlTest : public ::testing::Test { protected: void SetUp() override { cpuControl = new UpmCpuControl(); } void TearDown() override { delete cpuControl; } UpmCpuControl* cpuControl{nullptr}; }; // CPU核心数量测试 TEST_F(UpmCpuControlTest, CpuCoreNumTest) { EXPECT_GT(cpuControl->getCpuCoreNum(), 0); } // CPU核心策略测试 TEST_F(UpmCpuControlTest, CpuCorePolicyTest) { int coreNum = cpuControl->getCpuCoreNum(); for(int i = 0; i < coreNum; i++) { EXPECT_NO_THROW({ cpuControl->setCorePolicy(i, 1); cpuControl->setCoreMaxFreq(i, 2000000); int defaultFreq = cpuControl->getDefaultCoreMaxFreq(i); EXPECT_GT(defaultFreq, 0); cpuControl->setCoreDefaultMaxFreq(i); }); } } // 全局CPU策略测试 TEST_F(UpmCpuControlTest, AllCorePolicyTest) { EXPECT_NO_THROW({ cpuControl->setAllCorePolicy(1); cpuControl->setAllCoreMaxFreq(2000000); cpuControl->setAllCoreDefaultMaxFreq(); }); } // CPU占用参数配置测试 TEST_F(UpmCpuControlTest, CpuOccupyConfigTest) { EXPECT_NO_THROW(cpuControl->configCpuOccupyParameter( 1, // cpuPolicy 100, // cpuSamplingInterval 50, // offlineCpuOccupy 80, // onlineCpuOccupy 1 // reserveCoreNum )); }ukui-power-manager/tests/pciDeviceTest.cpp0000664000175000017500000000625615167661430017642 0ustar fengfeng#include "gtest/gtest.h" #include #include #include #include #include "../registeredQDbus/dev-power-control/pcidevice.h" class PciDeviceTest : public ::testing::Test { protected: void SetUp() override { // 创建临时测试目录 m_tempDir.reset(new QTemporaryDir()); ASSERT_TRUE(m_tempDir->isValid()); // 设置环境变量指向模拟目录 m_originalPath = qgetenv("PCI_DEVICE_PATH"); qputenv("PCI_DEVICE_PATH", m_tempDir->path().toUtf8() + "/sys/bus/pci/devices/"); // 创建完整的模拟环境 setupMockEnvironment(); // 初始化设备对象 m_device = new PciDevice(); } void TearDown() override { if (m_device) { delete m_device; m_device = nullptr; } // 恢复环境变量 if (m_originalPath.isEmpty()) { qunsetenv("PCI_DEVICE_PATH"); } else { qputenv("PCI_DEVICE_PATH", m_originalPath); } m_tempDir.reset(); } void setupMockEnvironment() { QString basePath = m_tempDir->path(); QDir dir; // 创建完整的PCI设备目录结构 QString devicePath = basePath + "/sys/bus/pci/devices/0000:00:00.0"; dir.mkpath(devicePath + "/power"); // 创建必要的文件和内容 createMockFile(devicePath + "/vendor", "0x8086"); createMockFile(devicePath + "/device", "0x1234"); createMockFile(devicePath + "/power/control", "auto"); createMockFile(devicePath + "/power/runtime_active_time", "1000"); createMockFile(devicePath + "/power/runtime_suspended_time", "500"); } void createMockFile(const QString &path, const QString &content) { QFile file(path); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { file.write(content.toUtf8()); file.close(); } } QScopedPointer m_tempDir; PciDevice* m_device{nullptr}; QByteArray m_originalPath; }; // 基本测试用例 TEST_F(PciDeviceTest, BasicTest) { ASSERT_NE(m_device, nullptr); EXPECT_GE(m_device->getPCIDeviceNum(), 0); } // 设备数量测试 TEST_F(PciDeviceTest, DeviceCountTest) { int count = m_device->getPCIDeviceNum(); EXPECT_GE(count, 0); qDebug() << "Device count:" << count; } // 测试电源状态设置 TEST_F(PciDeviceTest, PowerStateTest) { EXPECT_TRUE(m_device->setAllDevicePowerStat("auto")); EXPECT_FALSE(m_device->setAllDevicePowerStat("invalid")); } // 测试设备初始化 TEST_F(PciDeviceTest, Constructor) { EXPECT_NE(m_device, nullptr); } // 测试设备数量获取 TEST_F(PciDeviceTest, GetPCIDeviceNum) { EXPECT_GE(m_device->getPCIDeviceNum(), 0); } // 测试设置所有设备电源状态 TEST_F(PciDeviceTest, SetAllDevicePowerStat) { // 测试无效参数 EXPECT_FALSE(m_device->setAllDevicePowerStat("invalid")); // 测试有效参数 EXPECT_TRUE(m_device->setAllDevicePowerStat("auto")); EXPECT_TRUE(m_device->setAllDevicePowerStat("on")); EXPECT_TRUE(m_device->setAllDevicePowerStat("default")); } ukui-power-manager/tests/sysDbusRegisterTest.cpp0000664000175000017500000000316215167661430021101 0ustar fengfeng#include "gtest/gtest.h" #include "../registeredQDbus/sysdbusregister.h" class SysDbusRegisterTest : public ::testing::Test { protected: void SetUp() override { register_ = new SysdbusRegister(); } void TearDown() override { delete register_; } SysdbusRegister* register_{nullptr}; }; // 用户管理测试 TEST_F(SysDbusRegisterTest, UserManagementTest) { QString testUser = "testUser"; EXPECT_NO_THROW(register_->UserLogin(testUser)); EXPECT_NO_THROW(register_->UserActive(testUser)); EXPECT_NO_THROW(register_->UserLogout(testUser)); } // 亮度控制测试 TEST_F(SysDbusRegisterTest, BrightnessControlTest) { EXPECT_NO_THROW({ bool canSetBrightness = register_->CanSetBrightness(); if (canSetBrightness) { int maxBrightness = register_->GetMaxBrightness(); EXPECT_GT(maxBrightness, 0); int oldBrightness = register_->GetBrightnessPercent(); register_->SetBrightnessPercent(50); EXPECT_EQ(register_->GetBrightnessPercent(), 50); register_->SetBrightnessPercent(oldBrightness); } }); EXPECT_NO_THROW(register_->SetReduceBacklightSwitch(true)); } // 电源策略测试 TEST_F(SysDbusRegisterTest, PowerPolicyTest) { int oldCpuPolicy = register_->GetCpuPolicy(); EXPECT_NO_THROW({ register_->SetPcPolicy(1); register_->SetCpuPolicy(1); register_->SetGpuPolicy(1); register_->SetAudioPolicy(1); register_->SetAspmPolicy(1); }); EXPECT_EQ(register_->GetCpuPolicy(), 1); register_->SetCpuPolicy(oldCpuPolicy); }ukui-power-manager/tests/upmCustomHardwareConfigTest.cpp0000664000175000017500000000174715167661430022547 0ustar fengfeng#include "gtest/gtest.h" #include "../registeredQDbus/upmcustomhardwareconfig.h" class UpmCustomHardwareConfigTest : public ::testing::Test { protected: void SetUp() override { config = UpmCustomHardwareConfig::self(); } UpmCustomHardwareConfig* config{nullptr}; }; // 测试单例模式 TEST_F(UpmCustomHardwareConfigTest, SingletonTest) { EXPECT_NE(config, nullptr); EXPECT_EQ(config, UpmCustomHardwareConfig::self()); } // 测试硬件识别 TEST_F(UpmCustomHardwareConfigTest, HardwareDetectionTest) { bool isPangu = config->isPanguM900(); EXPECT_NO_THROW(isPangu); } // 测试扩展配置获取 TEST_F(UpmCustomHardwareConfigTest, ExtendConfigTest) { QString configKey = "test_key"; QString configValue; bool result = config->getExtendConfig(configKey, configValue); EXPECT_NO_THROW(result); // 测试空键 QString emptyKey; QString emptyValue; EXPECT_NO_THROW(config->getExtendConfig(emptyKey, emptyValue)); }ukui-power-manager/powermanagement.pro0000664000175000017500000000045115167661430017143 0ustar fengfengTEMPLATE = subdirs CONFIG += ordered SUBDIRS = \ registeredQDbus \ PowerManagementDaemon \ ukui-power-manager-tray \ ukui-upower\ power QMAKE_STRIP = unix:target_path=/usr/share/ukui-power-manager/tlp tlp.files = $$PWD/3rd/tlp/* tlp.path = $$target_path INSTALLS += tlp ukui-power-manager/data/0000775000175000017500000000000015167661415014144 5ustar fengfengukui-power-manager/data/99-upower-wake-up-usb-device.rules0000664000175000017500000000022515167661415022372 0ustar fengfengSUBSYSTEMS=="usb", ATTRS{product}=="*Mouse",ATTR{power/wakeup}="enabled" SUBSYSTEMS=="usb", ATTRS{product}=="*Keyboard",ATTR{power/wakeup}="enabled" ukui-power-manager/data/acme.ui0000664000175000017500000000213615167661415015412 0ustar fengfeng True 6 True audio-volume-high 6 0 True False False 1 ukui-power-manager/data/Makefile.am0000664000175000017500000000323415167661415016202 0ustar fengfeng#SUBDIRS = icons @INTLTOOL_DESKTOP_RULE@ desktopdir = $(datadir)/applications desktop_in_files = ukui-power-preferences.desktop.in \ ukui-power-statistics.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) @INTLTOOL_DESKTOP_RULE@ autostartdir = $(sysconfdir)/xdg/autostart autostart_in_files = ukui-power-manager.desktop.in \ ukui-power-manager-tray.desktop.in autostart_DATA = $(autostart_in_files:.desktop.in=.desktop) servicedir = $(DBUS_SERVICES_DIR) service_in_files = org.ukui.PowerManager.service.in service_DATA = $(service_in_files:.service.in=.service) $(service_DATA): $(service_in_files) Makefile @sed -e "s|\@servicedir\@|$(bindir)|" $< > $@ @GSETTINGS_RULES@ @INTLTOOL_XML_NOMERGE_RULE@ gsettings_schemas_in_files = org.ukui.power-manager.gschema.xml.in gsettings_SCHEMAS = $(gsettings_schemas_in_files:.xml.in=.xml) #kobe #confdir = $(sysconfdir)/polkit-1/localauthority/50-local.d #conf_DATA = com.ubuntu.enable-hibernate.pkla pkgdata_DATA = \ gpm-statistics.ui \ gpm-feedback-widget.ui \ gpm-prefs.ui \ acme.ui man_MANS = \ ukui-power-manager.1 \ ukui-power-manager-tray.1 \ ukui-power-backlight-helper.1 \ ukui-power-statistics.1 \ ukui-power-preferences.1 EXTRA_DIST = \ $(service_in_files) \ $(autostart_in_files) \ $(desktop_in_files) \ $(gsettings_schemas_in_files) \ $(pkgdata_DATA) \ $(man_MANS) # $(conf_DATA) clean-local : rm -f *~ DISTCLEANFILES = \ ukui-power-manager.desktop \ ukui-power-manager-tray.desktop \ ukui-power-preferences.desktop \ ukui-power-statistics.desktop \ org.ukui.PowerManager.service \ $(gsettings_SCHEMAS) ukui-power-manager/data/ukui-power-manager-tray.10000664000175000017500000000146315167661415020726 0ustar fengfeng.TH "UKUI-POWER-MANAGER-TRAY" "1" "29 March,2006" "" "" .SH NAME ukui-power-manager-tray \- UKUI power manager system tray .SH SYNOPSIS \fBukui-power-manager-tray\fR [ \fB\-\-verbose\fR ] [ \fB\-\-debug\fR ] [ \fB\-\-help\fR ] .SH "DESCRIPTION" \fBukui-power-manager-tray\fR is the panel applet of the UKUI power management. .PP It supports features such as suspending, hibernating, screen blanking, cpu frequency switching and more. .SH "OPTIONS" .TP \fB\-\-help\fR Show summary of options. .TP \fB\-\-verbose\fR Show extra debugging. .TP \fB\-\-debug\fR Only show specific debugging options. Useful for developers only. .SH "SEE ALSO" .PP ukui-power-preferences (1). .SH "AUTHOR" .PP This manual page was written by Oliver Grawert for the Debian system and updated by Ow Mun Heng ukui-power-manager/data/ukui-power-manager-tray.desktop.in.in0000664000175000017500000000064315167661415023250 0ustar fengfeng[Desktop Entry] _Name=Power Manager Tray Name[zh_CN]=电源管理程序 _Comment=Power management tray Icon=ukui-power-manager Exec=ukui-power-manager-tray Terminal=false Type=Application NoDisplay=true Categories= OnlyShowIn=UKUI; X-UKUI-Bugzilla-Bugzilla=UKUI X-UKUI-Bugzilla-Product=ukui-power-manager-tray X-UKUI-Bugzilla-Component=ukui-power-manager-tray X-UKUI-Bugzilla-Version=@VERSION@ X-UKUI-AutoRestart=true ukui-power-manager/data/ukui-power-preferences.desktop.in.in0000664000175000017500000000067215167661415023164 0ustar fengfeng[Desktop Entry] _Name=Power Management _Comment=Configure power management Icon=ukui-power-manager Exec=ukui-power-preferences Terminal=false Type=Application Categories=Settings;HardwareSettings; Keywords=UKUI;power;management;preferences;settings; OnlyShowIn=UKUI; StartupNotify=true X-UKUI-Bugzilla-Bugzilla=UKUI X-UKUI-Bugzilla-Product=ukui-power-manager X-UKUI-Bugzilla-Component=ukui-power-preferences X-UKUI-Bugzilla-Version=@VERSION@ ukui-power-manager/data/ukui-power-preferences.10000664000175000017500000000106115167661415020632 0ustar fengfeng.TH "UKUI-POWER-PREFERENCES" "1" "11 July, 2005" "" "" .SH NAME ukui-power-preferences \- UKUI power preferences GUI .SH SYNOPSIS \fBukui-power-preferences\fR [ \fB\-\-verbose\fR ] [ \fB\-\-help\fR ] .SH "DESCRIPTION" \fBukui-power-preferences\fR is the gui program for the ukui power management infrastructure .SH "OPTIONS" .TP \fB\-\-help\fR Show summary of options. .TP \fB\-\-verbose\fR Show extra debugging. .SH "SEE ALSO" .PP ukui-power-manager (1). .SH "AUTHOR" .PP This manual page was written by Oliver Grawert for the Debian system. ukui-power-manager/data/gpm-statistics.ui0000664000175000017500000007532315167661415017470 0ustar fengfeng False 6 Power Statistics center-on-parent dialog True False vertical 2 True False end gtk-help True True True False False True False False 0 True gtk-close True True True False False True False False 1 True False 6 6 True True never automatic in True True False False True 0 True True True True 9 automatic automatic in True True True False Details False True False 9 9 True False 12 True False 6 True False Graph type: False 0 True False 0 True True 1 True True 0 True False 6 True False Data length: False True 0 True False 0 True True 1 True True 1 False True 0 True False True False 6 True False y-axis 90 False True 0 True False There is no data to display. True True 1 True True 0 True False x-axis False True 1 True True 1 True False 6 True Use smoothed line True True False False True False True 0 Show data points True True False False True False True 1 False True 2 1 True False History 1 False True False 9 9 True False 6 True False Graph type: False True 0 True False 0 True True 1 False True 0 True False True False 6 True False y-axis 90 False True 0 True False There is no data to display. True True 1 True True 0 True False x-axis False True 1 True True 3 1 True False 6 True Use smoothed line True True False False True False True 0 Show data points True True False False True False True 1 False True 2 2 True False Statistics 2 False True False 9 9 True False 3 True False Processor wakeups per second: False True 0 True False 0 False True 1 False True 0 True True automatic automatic in True True True True 1 3 True False Wakeups 3 False True True 1 True True 1 button_help button_close ukui-power-manager/data/ukui-power-manager0000664000175000017500000000016515167661415017610 0ustar fengfeng/tmp/ukui-power-manager.log { daily rotate 7 compress notifempty maxsize 10M copytruncate } ukui-power-manager/data/org.ukui.PowerManager.service.in0000664000175000017500000000012015167661415022255 0ustar fengfeng[D-BUS Service] Name=org.ukui.PowerManager Exec=@servicedir@/ukui-power-manager ukui-power-manager/data/power-ignore.conf0000664000175000017500000000003615167661415017427 0ustar fengfeng[Login] HandlePowerKey=ignore ukui-power-manager/data/ukui-power-statistics.desktop.in.in0000664000175000017500000000066115167661415023053 0ustar fengfeng[Desktop Entry] _Name=Power Statistics _Comment=Observe power management Icon=ukui-power-statistics Exec=ukui-power-statistics Terminal=false Type=Application Categories=GTK;System;Monitor; OnlyShowIn=UKUI; NoDisplay=false StartupNotify=true X-UKUI-Bugzilla-Bugzilla=UKUI X-UKUI-Bugzilla-Product=ukui-power-manager X-UKUI-Bugzilla-Component=ukui-power-statistics X-UKUI-Bugzilla-Version=@VERSION@ X-Desktop-File-Install-Version=0.10 ukui-power-manager/data/ukui-power-policy.service0000664000175000017500000000032715167661415021134 0ustar fengfeng[Unit] Description=UKUI Power Policy daemon After=upower.service [Service] Type=dbus Restart=always RestartSec=0 BusName=ukui.power.policy ExecStart=/usr/bin/ukui-power-policy [Install] WantedBy=multi-user.target ukui-power-manager/data/gpm-prefs.ui0000664000175000017500000016745715167661415016427 0ustar fengfeng 1 1 61 1 5 23 1 61 1 5 41 100 1 5 1 1 61 1 5 23 1 61 1 5 1 1 61 1 5 23 1 61 1 5 5 Power Management Preferences False center-on-parent dialog True vertical 2 True True 6 True 12 vertical 12 True vertical 6 True 0 <b>Actions</b> True False False 0 True 12 True vertical 6 True 12 True True 0 Put computer to _sleep when inactive for: True False 0 True 1 False False 0 True 12 True True 0 When laptop lid is cl_osed: True False 0 True 1 1 False 1 False 0 True vertical 6 True 0 <b>Display</b> True False False 0 True 12 True vertical 5 True 12 True True 0 Put _display to sleep when inactive for: True False 0 True 1 0 True 12 True True 0 Set display _brightness to: True hscale_ac_brightness False 0 True True adjustment3 0 bottom 1 1 Di_m display when idle True True False True True False False 2 1 False 1 True On AC Power False True 12 vertical 12 True vertical 6 True 0 <b>Actions</b> True False False 0 True 12 True vertical 6 True 12 True True 0 Put computer to _sleep when inactive for: True False 0 True 1 False False 0 True 12 True True 0 When laptop lid is cl_osed: True False 0 True 1 1 True 12 True True 0 When battery po_wer is critically low: True False 0 True 1 2 False 1 False 0 True vertical 6 True 0 <b>Display</b> True False False 0 True 12 True vertical 5 True 12 True True 0 Put _display to sleep when inactive for: True False 0 True 1 0 _Reduce backlight brightness True True False True True False False 1 Di_m display when idle True True False True True False False 2 1 False 1 1 True On Battery Power 1 False True 12 vertical 12 True vertical 6 True 0 <b>Actions</b> True False False 0 True 12 True vertical 6 True 12 True True 0 Put computer to _sleep when inactive for: True False 0 True 1 False False 0 True 12 True True 0 When UPS power is l_ow: True False 0 True 1 1 True 12 True True 0 When UPS power is _critically low: True False 0 True 1 2 False 1 False 0 True vertical 6 True 0 <b>Display</b> True False False 0 True 12 True vertical 5 True 12 True True 0 Put _display to sleep when inactive for: True False 0 True 1 0 1 False 1 2 True On UPS Power 2 False True 12 vertical 12 True vertical 6 True 0 <b>Actions</b> True False False 0 True 12 True vertical 6 True 12 True True 0 When the power _button is pressed: True False 0 True 1 False False 0 True 12 True True 0 When the _suspend button is pressed: True False 0 True 1 1 False 1 False 0 True vertical 6 True 0 <b>Notification Area</b> True False False 0 True 12 True vertical 6 _Never display an icon True True False True True False False 0 _Only display an icon when battery power is low True True False True True radiobutton_notification_never False False 1 Only display an icon when charging or _discharging True True False True True radiobutton_notification_never False False 2 Only display an icon when a battery is p_resent True True False True True radiobutton_notification_never False False 3 _Always display an icon True True False True True radiobutton_notification_never False False 4 1 False 1 3 True General 3 False False 1 True end gtk-help True True True False Provides help about this program True False False 0 True Make Default True True True Sets this policy to be used by all users False False 1 gtk-close True True True True False Closes the program True False False 2 False end 0 button_help button_defaults button_close ukui-power-manager/data/gpm-feedback-widget.ui0000664000175000017500000000315415167661415020274 0ustar fengfeng Brightness notification True 0 out True 12 6 True 6 0 True 0.10000000149 False False 1 ukui-power-manager/data/ukui-power-backlight-helper.10000664000175000017500000000201015167661415021531 0ustar fengfeng.TH "UKUI-POWER-BACKLIGHT-HELPER" "1" "21 April, 2014" "" "" .SH NAME ukui-power-backlight-helper \- helper application for UKUI's power management backlight control .SH SYNOPSIS \fBukui-power-backlight-helper\fR [ \fB\-\-help\fR ] [ \fB\-\-set-brightness\fR ] [ \fB\-\-get-brightness\fR ] [ \fB\-\-get-max-brightness\fR ] .SH "DESCRIPTION" \fBukui-power-backlight-helper\fR is a helper utility for controlling the backlight of TFT displays via the UKUI power manager userspace daemon. .PP The \fBukui-power-backlight-helper\fR requires to be run with root privileges. .SH "OPTIONS" .TP \fB\-\-help\fR Show summary of options. .TP \fB\-\-set-brightness BRIGHTNESS_LEVEL\fR Set the given brightness. .TP \fB\-\-get-brightness\fR Get the current brightness. .TP \fB\-\-get-max-brightness\fR Get the number of brightness levels supported. .SH "SEE ALSO" .PP ukui-power-manager (1). .SH "AUTHOR" .PP This manual page has been written by Mike Gabriel for the Debian system (but may be used by others). ukui-power-manager/data/org.ukui.power-manager.gschema.xml.in0000664000175000017500000005000015167661415023202 0ustar fengfeng 'suspend' Whether to hibernate, suspend or do nothing when inactive The type of sleeping that should be performed when the computer is inactive. 'suspend' Battery critical low action The action to take when the battery is critically low. true If the battery event should occur when the lid is shut and the power disconnected If the battery lid close event should occur (for example 'Suspend when lid closed on battery') when the lid is previously shut and the AC power disconnected at a later time. 'suspend' Whether to hibernate, suspend or do nothing when inactive The type of sleeping that should be performed when the computer is inactive. 'shutdown' UPS critical low action The action to take when the UPS is critically low. 'hibernate' UPS low power action The action to take when the UPS is low. true Allow backlight brightness adjustment If the screen brightness should be changed when switching between AC and battery power. true Reduce the backlight brightness when on battery power If the screen should be reduced in brightness when the computer is on battery power. true Reduce the keyboard backlight when on battery power If the keyboard backlight brightness should be reduced when the computer is on battery power 100 Keyboard backlight brightness when on AC power. Percent brightness to set keyboard backlight at when on AC power. Legal values are between 0 and 100. 50 Percent to reduce keyboard backlight by when on battery power. The percentage to reduce the keyboard backlight by when on battery power. For example, if set to '60', the backlight will be cut by 40% on battery power. Legal values are between 0 and 100. 75 Percent to reduce keyboard backlight by when idle. The percentage to reduce the keyboard backlight by when idle. For example, if set to '60', the backlight will be cut by 40% when idle. Legal values are between 0 and 100. 100 The brightness of the screen when idle This is the laptop panel screen brightness used when the session is idle. Only valid when use-time-for-policy is true. true Dim the screen after a period of inactivity when on battery power If the screen should be dimmed to save power when the computer is idle when on battery power. 60 The default amount of time to dim the screen after idle The default amount of time to dim the screen after idle. 50 LCD dimming amount when on battery The amount to dim the brightness of the display when on battery power. Possible values are between 0 and 100. false Dim the screen after a period of inactivity when on AC power If the screen should be dimmed to save power when the computer is idle when on AC power. 'off' Method used to blank screen on AC The DPMS method used to blank the screen when on AC power. 'off' Method used to blank screen on battery The DPMS method used to blank the screen when on battery power. 100.0 LCD brightness when on AC The brightness of the display when on AC power. Possible values are between 0.0 and 100.0. 100.0 LCD brightness when on BAT The brightness of the display when on BAT power. Possible values are between 0.0 and 100.0. 'suspend' Suspend button action The action to take when the system suspend button is pressed. 'hibernate' Hibernate button action The action to take when the system hibernate button is pressed. 'interactive' Power button action The action to take when the system power button is pressed. 'suspend' Laptop lid close action on battery The action to take when the laptop lid is closed and the laptop is on battery power. 'suspend' Laptop lid close action when on AC The action to take when the laptop lid is closed and the laptop is on AC power. true Whether to use time-based notifications If time based notifications should be used. If set to false, then the percentage change is used instead, which may fix a broken ACPI BIOS. false Check CPU load before sleeping If the CPU load should be checked before doing the idle action. false Whether NetworkManager should be connected and disconnected on sleep. Whether NetworkManager should disconnect before suspending or hibernating and connect on resume. true Use ukui-screensaver lock setting Whether to use the screen lock setting of ukui-screensaver to decide if the screen is locked after a hibernate, suspend or blank screen. true Lock screen when blanked Whether the screen is locked when the screen is turned off. Only used if lock-use-screensaver is false. true Lock screen on suspend Whether the screen is locked when the computer wakes up from a suspend. Only used if lock-use-screensaver is false. true Lock screen on hibernate Whether the screen is locked when the computer wakes up from a hibernate. Only used if lock-use-screensaver is false. false Lock GNOME keyring on sleep Whether the GNOME keyring is locked before the computer enters suspend. This means the keyring will have to be unlocked on resume. true Lock GNOME keyring on sleep Whether the GNOME keyring is locked before the computer enters hibernate. This means the keyring will have to be unlocked on resume. true If we should show the low capacity warning for a broken battery If we should show the low capacity warning for a broken battery. true Notify when AC adapter is disconnected If the user should be notified when the AC adapter is disconnected. false Notify when fully charged If a notification message should be displayed when the battery is fully charged. true Notify on a sleep failure If a notification message should be displayed after suspend or hibernate failed. '' The URI to show to the user on sleep failure When sleep fails we can show the user a button to help fix the situation. Leave this blank if the button should not be shown. true Notify on a low power If a notification message should be displayed when the battery is getting low. true Whether we should show the history data points Whether we should show the history data points in the statistics window. true Whether we should smooth the history data Whether we should smooth the history data in the graph. 'power' The default graph type to show for history The default graph type to show in the history window. 21600 The maximum time displayed for history The maximum duration of time displayed on the x-axis of the history graph. true Whether we should show the stats data points Whether we should show the stats data points in the statistics window. true Whether we should smooth the stats data Whether we should smooth the stats data in the graph. 'power' The default graph type to show for stats The default graph type to show in the stats window. 0 The index of the page number to show by default The index of the page number to show by default which is used to return focus to the correct page. '' The ID of the last device selected The identifier of the last device which is used to return focus to the correct device. 20 Percentage considered low The percentage of the battery when it is considered low. Only valid when use-time-for-policy is false. 10 Percentage considered critical The percentage of the battery when it is considered critical. Only valid when use-time-for-policy is false. 5 Percentage action is taken The percentage of the battery when the critical action is performed. Only valid when use-time-for-policy is false. 1200 The time remaining when low The time remaining in seconds of the battery when it is considered low. Only valid when use-time-for-policy is true. 300 The time remaining when critical The time remaining in seconds of the battery when it is considered critical. Only valid when use-time-for-policy is true. 120 The time remaining when action is taken The time remaining in seconds of the battery when critical action is taken. Only valid when use-time-for-policy is true. 900 Sleep timeout computer when on battery The amount of time in seconds the computer on battery power needs to be inactive before it goes to sleep. 900 Sleep timeout computer when on AC The amount of time in seconds the computer on AC power needs to be inactive before it goes to sleep. 0 Sleep timeout computer when on UPS The amount of time in seconds the computer on UPS power needs to be inactive before it goes to sleep. 600 Sleep timeout display when on AC The amount of time in seconds before the display goes to sleep when the computer is on AC power. 600 Sleep timeout display when on battery The amount of time in seconds the computer on battery power needs to be inactive before the display goes to sleep. 600 Sleep timeout display when on UPS The amount of time in seconds the computer on UPS power needs to be inactive before the display goes to sleep. true If sounds should be used If sounds should be used when the power is critically low, or inhibit requests have stopped the policy action. true If preferences and statistics items should be shown in the context menu false If power policy mode should be auto switched when plugged in and out false If power policy mode should be auto switched when plugged in and out 2 power policy mode 1 power policy current 2 power policy current 1 power policy current 1 power policy current 1 power policy current 1 power policy current 'present' When to show the notification icon Display options for the notification icon. ukui-power-manager/data/ukui.power.policy.conf0000775000175000017500000000114315167661415020423 0ustar fengfeng ukui-power-manager/data/ukui-power-manager.desktop.in.in0000664000175000017500000000054015167661415022267 0ustar fengfeng[Desktop Entry] _Name=Power Manager _Comment=Power management daemon Icon=ukui-power-manager Exec= Terminal=false Type=Application NoDisplay=true Categories= OnlyShowIn=UKUI; X-UKUI-Bugzilla-Bugzilla=UKUI X-UKUI-Bugzilla-Product=ukui-power-manager X-UKUI-Bugzilla-Component=ukui-power-manager X-UKUI-Bugzilla-Version=@VERSION@ X-UKUI-AutoRestart=true ukui-power-manager/data/ukui-power-statistics.10000664000175000017500000000120315167661415020521 0ustar fengfeng.TH "UKUI-POWER-STATISTICS" "1" "11 December, 2007" "" "" .SH NAME ukui-power-statistics \- UKUI power statistics GUI .SH SYNOPSIS \fBukui-power-statistics\fR [ \fB\-\-verbose\fR ] [ \fB\-\-help\fR ] .SH "DESCRIPTION" \fBukui-power-statistics\fR is the gui program for the ukui power management infrastructure. .PP It allows users to visualize the power consumption of laptop hardware. .SH "OPTIONS" .TP \fB\-\-help\fR Show summary of options. .TP \fB\-\-verbose\fR Show extra debugging. .SH "SEE ALSO" .PP ukui-power-manager (1), ukui-power-preferences (1). .SH "AUTHOR" .PP This manual page was written by Simon Zheng . ukui-power-manager/data/ukui-power-manager.10000664000175000017500000000207415167661415017750 0ustar fengfeng.TH "UKUI-POWER-MANAGER" "1" "29 March,2006" "" "" .SH NAME ukui-power-manager \- UKUI power manager userspace daemon .SH SYNOPSIS \fBukui-power-manager\fR [ \fB\-\-verbose\fR ] [ \fB\-\-debug\fR ] [ \fB\-\-help\fR ] .SH "DESCRIPTION" \fBukui-power-manager\fR is the backend program of the UKUI power management infrastructure providing a complete and integrated solution to power management under the UKUI desktop environment. .PP It supports features such as suspending, hibernating, screen blanking, cpu frequency switching and more in one small neat package. .SH "OPTIONS" .TP \fB\-\-help\fR Show summary of options. .TP \fB\-\-verbose\fR Show extra debugging. .TP \fB\-\-no-daemon\fR Do not detach \fBukui-power-manager\fR into the background so that error messages will be displayed on console. .TP \fB\-\-debug\fR Only show specific debugging options. Useful for developers only. .SH "SEE ALSO" .PP ukui-power-preferences (1). .SH "AUTHOR" .PP This manual page was written by Oliver Grawert for the Debian system and updated by Ow Mun Heng