ukui-power-manager/ 0000775 0001750 0001750 00000000000 15167661430 013230 5 ustar feng feng ukui-power-manager/power/ 0000775 0001750 0001750 00000000000 15167661430 014364 5 ustar feng feng ukui-power-manager/power/translations/ 0000775 0001750 0001750 00000000000 15167661430 017105 5 ustar feng feng ukui-power-manager/power/translations/ky.ts 0000664 0001750 0001750 00000100406 15167661430 020101 0 ustar feng feng
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
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
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.ts 0000664 0001750 0001750 00000075705 15167661430 020474 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000101141 15167661430 020060 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000046003 15167661430 020105 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000100372 15167661430 020073 0 ustar feng feng
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
4ھ
5h
5ھ
Balance
声道平衡
Energy Efficiency
Performance
ئويۇن قويۇش
Performance Model
ئىقتىدار ئۈلگىسى
20min
20min
10minn
10分钟
15min
15min
30min
30min
1h
1ھ
2h
2ھ
10min
10min
Never
مەڭگۈ
100min
3分钟 {100m?}
3h
3ھ
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.ts 0000664 0001750 0001750 00000071660 15167661430 020447 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000102264 15167661430 020074 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000056421 15167661430 020476 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000076444 15167661430 020477 0 ustar feng feng
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.cpp 0000664 0001750 0001750 00000203452 15167661430 016232 0 ustar feng feng /* -*- 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.h 0000664 0001750 0001750 00000004264 15167661430 016503 0 ustar feng feng /* -*- 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.pro 0000664 0001750 0001750 00000003471 15167661430 016247 0 ustar feng feng QT += 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.h 0000664 0001750 0001750 00000006477 15167661430 017563 0 ustar feng feng /* -*- 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.h 0000664 0001750 0001750 00000017163 15167661430 015701 0 ustar feng feng /* -*- 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-format 0000664 0001750 0001750 00000017710 15167661415 015614 0 ustar feng feng ---
# 语言: 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.md 0000664 0001750 0001750 00000000364 15167661415 015015 0 ustar feng feng ## dbus 服务
```
用于提权
使用方法:
mkdir build
make -j8
sudo make install //这样会讲service文件安装到系统目录下
调用exitService接口退出 //或者重启,否则修改无法生效(注销也不生效)
```
ukui-power-manager/shared/ 0000775 0001750 0001750 00000000000 15167661430 014476 5 ustar feng feng ukui-power-manager/shared/include/ 0000775 0001750 0001750 00000000000 15167661430 016121 5 ustar feng feng ukui-power-manager/shared/include/dmi_chassis_type.h 0000664 0001750 0001750 00000002456 15167661430 021630 0 ustar feng feng /*
* 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/ 0000775 0001750 0001750 00000000000 15167661415 014000 5 ustar feng feng ukui-power-manager/doc/性能测试注意事项.md 0000664 0001750 0001750 00000001126 15167661415 025056 0 ustar feng feng # 性能测试注意事项
```
1.连接电源【使用电池的情况下电源管理会更改调频策略】
2.控制面板设置电源计划为性能模式
如果控制面板-系统-电源-使用电源时的模式选择没有性能模式则需要手动设置【v10sp1 0820-1 版本暂时没有性能模式选项】
gsettings set org.ukui.power-manager power-policy-ac 0
3.控制面板-系统-电源-此时间段后关闭显示器 选为从不
4.控制面板-系统-电源-此时间段后进入睡眠 选为从不
5.控制面板-个性化-屏保-此时间段后开启屏保 选为从不
```
ukui-power-manager/doc/schedules.md 0000664 0001750 0001750 00000004040 15167661415 016277 0 ustar feng feng ## 计划表
```
计划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/设计文档.md 0000664 0001750 0001750 00000000033 15167661415 020665 0 ustar feng feng # 电源管理设计文档
ukui-power-manager/doc/电源管理需求文档.md 0000664 0001750 0001750 00000003515 15167661415 024743 0 ustar feng feng # 电源管理需求文档
### 目录
```
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/ 0000775 0001750 0001750 00000000000 15167661430 014003 5 ustar feng feng ukui-power-manager/man/ukui-power-manager-tray.1 0000664 0001750 0001750 00000001430 15167661415 020562 0 ustar feng feng .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.1 0000664 0001750 0001750 00000001365 15167661415 021677 0 ustar feng feng .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.2 0000664 0001750 0001750 00000001402 15167661430 017602 0 ustar feng feng .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.1 0000664 0001750 0001750 00000001374 15167661415 020241 0 ustar feng feng .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.1 0000664 0001750 0001750 00000001361 15167661415 016365 0 ustar feng feng .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.1 0000664 0001750 0001750 00000001360 15167661415 017607 0 ustar feng feng .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/ 0000775 0001750 0001750 00000000000 15167661430 017724 5 ustar feng feng ukui-power-manager/ukui-power-manager-tray/divider.cpp 0000664 0001750 0001750 00000002226 15167661430 022060 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000015645 15167661430 023050 0 ustar feng feng /*
* 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.h 0000664 0001750 0001750 00000001657 15167661415 021537 0 ustar feng feng /*
* 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.h 0000664 0001750 0001750 00000006252 15167661430 022507 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000051733 15167661430 023034 0 ustar feng feng /*
* 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/ 0000775 0001750 0001750 00000000000 15167661430 022445 5 ustar feng feng ukui-power-manager/ukui-power-manager-tray/translations/ukui-power-manager-tray_zh_CN.ts 0000664 0001750 0001750 00000024505 15167661430 030600 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000030562 15167661430 030603 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000023500 15167661430 030203 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000030506 15167661430 030555 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000017116 15167661430 030204 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000024323 15167661430 030222 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000022254 15167661430 030214 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000024502 15167661430 030577 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000017116 15167661430 030216 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000021550 15167661430 030176 0 ustar feng feng
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/ 0000775 0001750 0001750 00000000000 15167661415 021741 5 ustar feng feng ukui-power-manager/ukui-power-manager-tray/resources/ukui-power-manager-tray.desktop 0000664 0001750 0001750 00000000643 15167661415 030033 0 ustar feng feng [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/ 0000775 0001750 0001750 00000000000 15167661430 022200 5 ustar feng feng ukui-power-manager/ukui-power-manager-tray/upower-dbus/upowerlinepowerdbus.cpp 0000664 0001750 0001750 00000007024 15167661430 027033 0 ustar feng feng /*
* 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.h 0000664 0001750 0001750 00000003554 15167661430 026152 0 ustar feng feng /*
* 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.h 0000664 0001750 0001750 00000004112 15167661430 024546 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000012707 15167661430 025112 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000010310 15167661430 026471 0 ustar feng feng /*
* 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.h 0000664 0001750 0001750 00000004461 15167661430 025436 0 ustar feng feng /*
* 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.h 0000664 0001750 0001750 00000002552 15167661430 026501 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000020154 15167661430 025766 0 ustar feng feng /*
* 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.h 0000664 0001750 0001750 00000002534 15167661430 021524 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000003737 15167661430 021366 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000006427 15167661430 022064 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000052633 15167661430 023025 0 ustar feng feng /*
* 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.pro 0000664 0001750 0001750 00000006110 15167661430 025140 0 ustar feng feng #-------------------------------------------------
#
# 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.h 0000664 0001750 0001750 00000020157 15167661430 022475 0 ustar feng feng /*
* 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.h 0000664 0001750 0001750 00000004627 15167661430 022142 0 ustar feng feng /*
* 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.h 0000664 0001750 0001750 00000010032 15167661430 022455 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000036112 15167661430 022467 0 ustar feng feng /*
* 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/ 0000775 0001750 0001750 00000000000 15167661430 022532 5 ustar feng feng ukui-power-manager/ukui-power-manager-tray/upm-gsettings/upm_gsettings.h 0000664 0001750 0001750 00000006754 15167661430 025607 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000014216 15167661430 026132 0 ustar feng feng /*
* 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/ 0000775 0001750 0001750 00000000000 15167661430 013720 5 ustar feng feng ukui-power-manager/3rd/tlp/ 0000775 0001750 0001750 00000000000 15167661430 014517 5 ustar feng feng ukui-power-manager/3rd/tlp/func.d/ 0000775 0001750 0001750 00000000000 15167661430 015674 5 ustar feng feng ukui-power-manager/3rd/tlp/func.d/30-tlp-func-rf-sw 0000664 0001750 0001750 00000033733 15167661430 020634 0 ustar feng feng #!/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-bay 0000664 0001750 0001750 00000014311 15167661430 020341 0 ustar feng feng #!/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-stat 0000664 0001750 0001750 00000062655 15167661430 020336 0 ustar feng feng #!/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-cpu 0000664 0001750 0001750 00000043060 15167661430 020355 0 ustar feng feng #!/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-usb 0000664 0001750 0001750 00000024767 15167661430 020375 0 ustar feng feng #!/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-disk 0000664 0001750 0001750 00000053211 15167661430 020524 0 ustar feng feng #!/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-pm 0000664 0001750 0001750 00000020300 15167661430 020176 0 ustar feng feng #!/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-batt 0000664 0001750 0001750 00000014530 15167661430 020527 0 ustar feng feng #!/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-rf 0000664 0001750 0001750 00000011451 15167661430 020202 0 ustar feng feng #!/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-gpu 0000664 0001750 0001750 00000023052 15167661430 020370 0 ustar feng feng #!/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/tlp 0000775 0001750 0001750 00000037010 15167661430 015245 0 ustar feng feng #!/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-readconfs 0000775 0001750 0001750 00000017716 15167661430 017222 0 ustar feng feng #!/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.sh 0000775 0001750 0001750 00000001332 15167661430 020540 0 ustar feng feng #!/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/ 0000775 0001750 0001750 00000000000 15167661430 015507 5 ustar feng feng ukui-power-manager/3rd/tlp/bat.d/35-lg 0000664 0001750 0001750 00000042652 15167661430 016272 0 ustar feng feng #!/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-legacy 0000664 0001750 0001750 00000040465 15167661430 017535 0 ustar feng feng #!/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-macbook 0000664 0001750 0001750 00000053020 15167661430 017270 0 ustar feng feng #!/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-asus 0000664 0001750 0001750 00000042404 15167661430 016647 0 ustar feng feng #!/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-thinkpad 0000664 0001750 0001750 00000150026 15167661430 017462 0 ustar feng feng #!/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-sony 0000664 0001750 0001750 00000040413 15167661430 016645 0 ustar feng feng #!/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-huawei 0000664 0001750 0001750 00000043173 15167661430 017143 0 ustar feng feng #!/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-lenovo 0000664 0001750 0001750 00000040305 15167661430 017161 0 ustar feng feng #!/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-generic 0000664 0001750 0001750 00000016432 15167661430 017302 0 ustar feng feng #!/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-legacy 0000664 0001750 0001750 00000104317 15167661430 020722 0 ustar feng feng #!/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-samsung 0000664 0001750 0001750 00000040203 15167661430 017326 0 ustar feng feng #!/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-msi 0000664 0001750 0001750 00000047004 15167661430 016453 0 ustar feng feng #!/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-toshiba 0000664 0001750 0001750 00000042517 15167661430 017316 0 ustar feng feng #!/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/TEMPLATE 0000664 0001750 0001750 00000054377 15167661430 016665 0 ustar feng feng #!/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-system76 0000664 0001750 0001750 00000052251 15167661430 017366 0 ustar feng feng #!/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.conf 0000664 0001750 0001750 00000003054 15167661430 017177 0 ustar feng feng # /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-base 0000664 0001750 0001750 00000075507 15167661430 017120 0 ustar feng feng #!/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/ 0000775 0001750 0001750 00000000000 15167661430 015660 5 ustar feng feng ukui-power-manager/plugin-power/translations/ 0000775 0001750 0001750 00000000000 15167661430 020401 5 ustar feng feng ukui-power-manager/plugin-power/translations/ar.ts 0000664 0001750 0001750 00000031155 15167661430 021360 0 ustar feng feng
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.ts 0000664 0001750 0001750 00000030256 15167661430 021375 0 ustar feng feng
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/ 0000775 0001750 0001750 00000000000 15167661430 015524 5 ustar feng feng ukui-power-manager/ukui-upower/ukui-upower.pro 0000664 0001750 0001750 00000002250 15167661430 020541 0 ustar feng feng #-------------------------------------------------
#
# 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.h 0000664 0001750 0001750 00000000557 15167661430 016641 0 ustar feng feng #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.md 0000664 0001750 0001750 00000000476 15167661430 017012 0 ustar feng feng A.使用工具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/ 0000775 0001750 0001750 00000000000 15167661430 020052 5 ustar feng feng ukui-power-manager/ukui-upower/batteryinfo/batteryinfo.h 0000664 0001750 0001750 00000005552 15167661430 022560 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000021113 15167661430 023102 0 ustar feng feng /*
* 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.h 0000664 0001750 0001750 00000005270 15167661415 020671 0 ustar feng feng /*
* 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/ 0000775 0001750 0001750 00000000000 15167661430 017536 5 ustar feng feng ukui-power-manager/ukui-upower/resources/99-upower-wake-up-usb-device.rules 0000664 0001750 0001750 00000000225 15167661415 025767 0 ustar feng feng SUBSYSTEMS=="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.desktop 0000664 0001750 0001750 00000000257 15167661415 023434 0 ustar feng feng [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.xml 0000664 0001750 0001750 00000053350 15167661430 026202 0 ustar feng feng
'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.conf 0000664 0001750 0001750 00000000204 15167661415 022311 0 ustar feng feng Section "ServerFlags"
option "StandbyTime" "0"
option "SuspendTime" "0"
option "OffTime" "0"
option "BlankTime" "0"
EndSection
ukui-power-manager/ukui-upower/main.cpp 0000664 0001750 0001750 00000003273 15167661430 017161 0 ustar feng feng /*
* 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.xml 0000664 0001750 0001750 00000002431 15167661415 021334 0 ustar feng feng
ukui-power-manager/ukui-upower/upowerdbus.h 0000664 0001750 0001750 00000004160 15167661430 020075 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000003650 15167661430 020433 0 ustar feng feng /*
* 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/ 0000775 0001750 0001750 00000000000 15167661430 017014 5 ustar feng feng ukui-power-manager/ukui-upower/common/common.h 0000664 0001750 0001750 00000002265 15167661430 020462 0 ustar feng feng /*
* 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.cpp 0000664 0001750 0001750 00000003534 15167661430 020565 0 ustar feng feng #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/ 0000775 0001750 0001750 00000000000 15167661430 017721 5 ustar feng feng ukui-power-manager/ukui-upower/upowerinfo/upowerinfo.cpp 0000664 0001750 0001750 00000016342 15167661430 022630 0 ustar feng feng /*
* 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.h 0000664 0001750 0001750 00000005027 15167661430 022273 0 ustar feng feng /*
* 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.xml 0000664 0001750 0001750 00000002025 15167661415 021146 0 ustar feng feng